Code Golf: Parser

Discussion in 'Programming' started by glatteis, May 16, 2016.

  1. I thought I'd make another code golf! Rules are here: http://glatteis.bplaced.net/CodeGolf

    This time, the task is to make a method (or function) that takes a string containing an expression that follows the rules stated below. It should return a double (or number) that is the solution of the evaluated expression.

    Code (Text):
    The parser should parse expressions of the following pattern: There are four functions, which are add, sub, mul and div. They add, subtract, multiply and divide respectively. All of the functions take two arguments. Example:

    'add 5 8' should return 5 + 8, which is 13.
    'div 8 2' should return 8 / 2, which is 4.
    'mul 6 0.5' should return 6 * 0.5, which should be about 3.

    (the method should not return the calculations but the solutions.)

    Arguments of functions themselves can be solutions of functions. Example:

    'mul add 4 7 2' should return (4+7) * 2, which is 22.

    Special handling of dividing by 0 is not nessecary.
    Happy golfing! The golf ends in one or two weeks, depending on how many people want to participate.
     
    • Like Like x 1
    • Agree Agree x 1
  2. I have been waiting for you to do this :/
    Even though I suck lol
     
  3. I did the first part, but rqed at the second.
     
  4. I have yet to try this myself. I will do that now.
     
  5. Reference ruby implementation I did:
    Code (Text):
    # @return [int]
    # @param [String] expression
    def parse(expression)
      a = expression.split(' ')
      (a.length - 1).downto(1).each do |i|
        unless is_number?(a[i])
          sol = parse(a.slice(i, i+2).join(' '))
          a.delete_at(i)
          a.delete_at(i + 1)
          a.delete_at(i + 2)
          a[i] = sol
          return parse a.join(' ')
        end
      end

      b = a[1].to_f
      c = a[2].to_f

      case a[0]
        when 'add'
          b + c
        when 'sub'
          b - c
        when 'div'
          b / c
        when 'mul'
          b * c
        else
          -1
      end

    end

    def is_number?(s)
      true if Float(s) rescue false
    end
    Not very short though :D
     
    • Agree Agree x 1
  6. I think I can do the part with one function, but not two. Does it have to be able to do more than 2 so 5 functions or only a max of two?
     
  7. My attempt in C#
    Code (C#):
    int Parse(string input)
    {
        Stack<string> op = new Stack<string>();
        List<double> args = new List<double>();

        foreach (string part in input.Split(' '))
        {
            switch (part)
            {
                case "add": case "sub": case "mul": case "div":
                    op.Push(part);
                    break;
                default:
                    args.Add(Convert.ToDouble(part));
                    break;
            }
        }

        Stack<double> stack = new Stack<double>(args.Reverse<double>());

        while (op.Count > 0)
        {
            switch (op.Pop())
            {
                case "add":
                    stack.Push(stack.Pop() + stack.Pop());
                    break;
                case "sub":
                    stack.Push(stack.Pop() - stack.Pop());
                    break;
                case "mul":
                    stack.Push(stack.Pop() * stack.Pop());
                    break;
                case "div":
                    stack.Push(stack.Pop() / stack.Pop());
                    break;
            }
        }
        return Convert.ToInt32(stack.Pop());
    }
    Mine isn't very short either :p
     
    #7 Rezz, May 21, 2016
    Last edited: May 22, 2016
    • Agree Agree x 1
  8. FormallyMyles

    Supporter

    I decided to code this in JavaScript to show you how broken JavaScript can be.
    Code (Java):
    function parse(input) {
        var opStack = [], argStack = [], token = input.split(' ');
        for (var o in token)
            isNaN(token[o]) ? opStack.push(token[o]) : argStack.unshift(parseFloat(token[o]));
        for (opStack.length > 0; o = opStack.pop();)
            argStack.push(eval("argStack.pop() " + (o == "add" ? "+" : o == "sub" ? "-" : o == "mul" ? "*" : "/") + " argStack.pop()"));
        return argStack.pop();
    }
    Here's a happy list of abuse in those lines of code:
    • Single line variable assignment abuse
    • Ternary abuse
    • Eval abuse
    • Single line blocks abuse

    I'm probably satan for abusing JavaScript. There's argument it could be slightly shorter but hey ;)

    Edit:
    Code (Java):
    function parse(e){var z=[],a=[],k=e.split(" ");for(var o in k)isNaN(k[o])?z.push(k[o]):a.unshift(parseFloat(k[o]));for(z.length>0;o=z.pop();)a.push(eval("a.pop() "+("add"==o?"+":"sub"==o?"-":"mul"==o?"*":"/")+" a.pop()"));return a.pop()};
    (Tested in browsers)
     
    #8 FormallyMyles, May 22, 2016
    Last edited: May 22, 2016
    • Like Like x 1
  9. Redid mine to solve recursively :eek:

    Code (C#):
    int Parse(string[] input)
    {
        string[] args = input[0].Split(' ');
        switch (args[0])
        {
            case "add": case "sub": case "mul": case "div":
                string[] pass = new string[input.Count() + 1];
                for (int i = 0; i < pass.Count(); i++)
                {
                    pass[i] = (i == 0) ? input[0].Substring(4) : ((i == input.Count()) ? args[0] : input[i]);
                }
                return Parse(pass);
            default:
                Stack<double> operands = new Stack<double>(args.Select(arg => Convert.ToDouble(arg)).Reverse());
                for (int i = input.Count() - 1; i > 0; i--)
                {
                    switch (input[i])
                    {
                        case "add":
                            operands.Push(operands.Pop() + operands.Pop()); break;
                        case "sub":
                            operands.Push(operands.Pop() - operands.Pop()); break;
                        case "mul":
                            operands.Push(operands.Pop() * operands.Pop()); break;
                        case "div":
                            operands.Push(operands.Pop() / operands.Pop()); break;
                    }
                }
                return Convert.ToInt32(operands.Pop());
        }
    }
    ^ I managed to take off 9 lines from my previous one.
     
    #9 Rezz, May 22, 2016
    Last edited: May 22, 2016
  10. Here's a java one that's probably not as concise as could be but 473 characters:
    Code (Text):
        public static float p(String i){
            String[] d = i.split(" ");
            int o = d.length - 3;
            float c = m(d[0], Float.valueOf(d[1]), Float.valueOf(d[2]));
            for (int n = 0; n < o; n++){
                c = m(d[0], c, Float.valueOf(d[3+n]));
            }
            return c;
        }

        public static float m(String t, float x, float y){
            return (t.equals("mul") ? x * y : t.equals("add") ? x + y : t.equals("sub") ? x - y: t.equals("div") ? x/y:0);
        }
    m() is a utility method. it works recursively for any amount of numbers inputted
    EDIT: Better (longer :() version down below that does the arguments.
     
    #10 akselm, May 22, 2016
    Last edited: May 22, 2016
  11. Oh lord... what have you done.
     
  12. That won't work if it's something like "mul add 4 7 2"

    EDIT: My entry will come.
     
  13. New version that supports multiple arguments (oops) 620 characters, i bet it could be shorter.
    Code (Text):
        public static float p(String i){
            String[] d = i.split(" ");
            int l = 0;
            for (int n = 0; n < d.length; n++) if (!d[n].matches("-?\\d+(.\\d+)?")) l = n;
            int o = d.length - 3 - l;
            float c = m(d[0], Float.valueOf(d[l+1]), Float.valueOf(d[l+2]));
            for (int n = 0; n < o; n++){
                c = m((l > 0 && l-n >= 0) ? d[l+n] : d[0], c, Float.valueOf(d[n+3+l]));
            }
            return c;
        }

        public static float m(String t, float x, float y){
            return (t.equals("mul") ? x * y : t.equals("add") ? x + y : t.equals("sub") ? x - y: t.equals("div") ? x/y:0);
        }
     
    #13 akselm, May 22, 2016
    Last edited: May 22, 2016
  14. In Java 399 characters, supports one or more calculations inside each other. (Completely changed all variables and removed spaces).
    Code (Text):
    class A{public static void main(String[]a){int b=0;while(a[b].matches("^[a-zA-Z]*$"))b++;b--;float c=0;int d=b+1;boolean e=true;do{if(e){c=a(a[b],Float.valueOf(a[d]),Float.valueOf(a[d+1]));e=false;d+=2;}else{c=a(a[b],c,Float.valueOf(a[d]));d++;}b--;}while(b>=0);System.out.println(c);}static float a(String a,float b,float c){return a.equals("add")?b+c:a.equals("sub")?b-c:a.equals("mul")?b*c:b/c;}}
    Best of all it uses the default arguments from the java main method, so I don't have to split it myself :). This is the code with spaces:
    Code (Text):
    class A {
        public static void main(String[] a) {
            int b = 0;
            while(a[b].matches("^[a-zA-Z]*$"))
                b++;
            b--;
            float c = 0;
            int d = b + 1;
            boolean e = true;
            do {
                if (e) {
                    c = a(a[b], Float.valueOf(a[d]), Float.valueOf(a[d + 1]));
                    e = false;
                    d += 2;
                } else {
                    c = a(a[b], c, Float.valueOf(a[d]));
                    d++;
                }
                b--;
            } while (b>=0);
            System.out.println(c);
        }
     
        static float a(String a, float b, float c) {
            return a.equals("add") ? b + c : a.equals("sub") ? b - c : a.equals("mul") ? b * c : b / c;
        }
    }
     
  15. Yeah, I found an easier method, with only 324 characters! This is it:
    Code (Text):
    class A{public static void main(String[]a){int b=0;while(a[b].matches("^[a-zA-Z]*$"))b++;b--;int d=b+1;float c=Float.valueOf(a[d]);do{d++;c=a(a[b],c,Float.valueOf(a[d]));b--;}while(b>=0);System.out.println(c);}static float a(String a,float b,float c){return a.equals("add")?b+c:a.equals("sub")?b-c:a.equals("mul")?b*c:b/c;}}
    The whole code with spaces:
    Code (Text):
    class A {
        public static void main(String[] a) {
            int b = 0;
            while(a[b].matches("^[a-zA-Z]*$"))
                b++;
            b--;
            int d = b + 1;
            float c = Float.valueOf(a[d]);
            do {
                d++;
                c = a(a[b], c, Float.valueOf(a[d]));
                b--;
            } while (b >= 0);
            System.out.println(c);
        }
       
        static float a(String a, float b, float c) {
            return a.equals("add") ? b + c : a.equals("sub") ? b - c : a.equals("mul") ? b * c : b / c;
        }
    }
     
  16. A lot of posting, but I found a shorter way. I won't rest 'till it fits in a Twitter message :p. It's now only 282 characters. But aside of that here it is:
    Code (Text):
    class A{public static void main(String[]a){int b=0;while(a[b].matches("^[a-zA-Z]*$"))b++;b--;int d=b+1;float c=Float.valueOf(a[d]);do{d++;float e=Float.valueOf(a[d]);c=a[b].equals("add")?c+e:a[b].equals("sub")?c-e:a[b].equals("mul")?c*e:c/e;b--;}while(b>=0);System.out.println(c);}}
    Here is it again with spaces:
    Code (Text):
    class A {
        public static void main(String[] a) {
            int b = 0;
            while(a[b].matches("^[a-zA-Z]*$"))
                b++;
            b--;
            int d = b + 1;
            float c = Float.valueOf(a[d]);
            do {
                d++;
                float e = Float.valueOf(a[d]);
                c = a[b].equals("add") ? c + e : a[b].equals("sub") ? c - e : a[b].equals("mul") ? c * e : c / e;
                b--;
            } while(b >= 0);
            System.out.println(c);
        }
    }
     
    • Like Like x 1
  17. No max!
     
  18. You don't have to declare static or the class. It could just begin with:
    Code (Text):
    double main(String[] a)
    Keep in mind that I want a String, not an array of Strings! The method should also return an double or float, not print it.
    EDIT: mul add 4 8 div 4 2 throws an exception
     
    #18 glatteis, May 23, 2016
    Last edited: May 23, 2016
  19. mul add 4 8 div 4 2 returns 9, should return 24 D:
     
  20. mul add 4 8 div 4 2 returns 8, should return 24 D: