2

am stuck while writing a visitor for my antlr program, for an expression like

multiplyingExpression ((PLUS | MINUS) multiplyingExpression)*

i want to get the left part of the expression, get the operator type and the right part of the expression, any help please. this is what i have so far

private double WalkLeft(testGrammerParser.MultiplyingExpressionContext context)
        {
            return Visit(context.GetRuleContext<testGrammerParser.MultiplyingExpressionContext>(0));
        }

        private double WalkRight(testGrammerParser.MultiplyingExpressionContext context)
        {
            return Visit(context.GetRuleContext<testGrammerParser.MultiplyingExpressionContext>(1));
        }

and the error am getting is Object reference not set to an instance of an object.

Thanks in advance.

EDIT

Am more looking of something like this

public Integer visitMulDiv(LabeledExprParser.MulDivContext ctx) {
    int left = visit(ctx.expr(0)); // get value of left subexpression
    int right = visit(ctx.expr(1)); // get value of right subexpression
    if ( ctx.op.getType() == LabeledExprParser.MUL ) return left * right; //check operation type
    return left / right; // must be DIV
}

EDIT 2 (grammer)

This is the grammer that am using

grammar testGrammer;

/*
 * Parser Rules
 */

 compileUnit
    :   expression + EOF
    ;

expression
   : multiplyingExpression ((PLUS | MINUS) multiplyingExpression)*
   ;

multiplyingExpression
   : powExpression ((TIMES | DIV) powExpression)*
   ;

powExpression
   : atom (POW atom)*
   ;

atom
   : scientific
   | variable
   | LPAREN expression RPAREN
   | func
   ;

scientific
   : number (E number)?
   ;

func
   : funcname LPAREN expression RPAREN
   ;

funcname
   : COS
   | TAN
   | SIN
   | ACOS
   | ATAN
   | ASIN
   | LOG
   | LN
   ;

number
   : MINUS? DIGIT + (POINT DIGIT +)?
   ;

variable
   : MINUS? LETTER (LETTER | DIGIT)*
   ;

COS
   : 'cos'
   ;

SIN
   : 'sin'
   ;

TAN
   : 'tan'
   ;

ACOS
   : 'acos'
   ;

ASIN
   : 'asin'
   ;

ATAN
   : 'atan'
   ;

LN
   : 'ln'
   ;

LOG
   : 'log'
   ;

LPAREN
   : '('
   ;

RPAREN
   : ')'
   ;

PLUS
   : '+'
   ;

MINUS
   : '-'
   ;

TIMES
   : '*'
   ;

DIV
   : '/'
   ;

POINT
   : '.'
   ;

E
   : 'e' | 'E'
   ;

POW
   : '^'
   ;

LETTER
   : ('a' .. 'z') | ('A' .. 'Z')
   ;

DIGIT
   : ('0' .. '9')
   ;

/*
 * Lexer Rules
 */

WS
    :[ \r\n\t] + -> channel(HIDDEN)
    ;
lulliezy
  • 1,204
  • 3
  • 18
  • 36
  • Possible duplicate of [What is a NullReferenceException, and how do I fix it?](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – Cee McSharpface May 09 '17 at 15:53
  • saw the link but with mine am actually asking how to access the left, right and operation values @dlatikay – lulliezy May 09 '17 at 16:04
  • 1
    The Kleene star `*` in your expression makes the right part optional (or more precisely it can occur 0 or more times). You *can* get `null` values from `.GetRuleContext<...>(1)` and you didn't account for it. You also did not account for additional occurrences (ie `n > 1`). – Lucas Trzesniewski May 09 '17 at 21:29
  • okay I didn't see that, but when I debug, for expression `3*3` I get 3 children but using the context I get null, why is that? @LucasTrzesniewski – lulliezy May 10 '17 at 07:08
  • I don't know - since you didn't post the full grammar anything I'd say would be a guess. But as you seem to be implementing math stuff, I can point you towards an [answer of mine here](http://stackoverflow.com/a/29996191/3764814) though which shows you how to implement a simple calculator - there's a math grammar there you can take a look at, you can ignore all the AST stuff if you don't need it. – Lucas Trzesniewski May 10 '17 at 07:48
  • Edited the question my grammar is also a bit complicated, what I have so far is `public override double VisitExpression(testGrammerParser.ExpressionContext context) { var left = context.multiplyingExpression(0); var right = context.multiplyingExpression(1); if (right != null) { if (context.PLUS(0) == null) { return Visit(left) - Visit(right); } return Visit(left) + Visit(right); } return Visit(left); }` – lulliezy May 10 '17 at 08:47

1 Answers1

3

I finally did it, and here is the full visitor class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ExpressionParser
{
    class testVisitor: testGrammerBaseVisitor<double>
    {
        public override double VisitCompileUnit(testGrammerParser.CompileUnitContext context)
        {
            return Visit(context.expression(0));
        }

        public override double VisitExpression(testGrammerParser.ExpressionContext context)
        {
            var left = context.multiplyingExpression(0);
            var right = context.multiplyingExpression(1);

            if (right != null)
            {
                if (context.PLUS(0) == null)
                {
                    return Visit(left) - Visit(right);
                }

                return Visit(left) + Visit(right);
            }

            return Visit(left);
        }

        public override double VisitMultiplyingExpression(testGrammerParser.MultiplyingExpressionContext context)
        {
            var left = context.powExpression(0);
            var right = context.powExpression(1);

            if (right != null)
            {
                if (context.DIV(0) == null)
                {
                    return Visit(left) * Visit(right);
                }

                return Visit(left) / Visit(right);
            }

            return Visit(left);
        }

        public override double VisitPowExpression(testGrammerParser.PowExpressionContext context)
        {
            var left = context.atom(0);
            var right = context.atom(1);

            if (right != null)
            {
                return Math.Pow(Visit(left), Visit(right));
            }

            return Visit(left);
        }

        public override double VisitAtom(testGrammerParser.AtomContext context)
        {
            if (context.scientific() != null)
            {
                return Visit(context.scientific());
            }

            if (context.variable() != null)
            {
                return Visit(context.variable());
            }

            if (context.expression() != null) //need to check this out
            {
                return Visit(context.expression());
            }

            return Visit(context.func());
        }

        public override double VisitScientific(testGrammerParser.ScientificContext context)
        {
            var left = context.number(0);
            var right = context.number(1);

            if (right != null)
            {
                return Visit(left) * Math.E * Visit(right);
            }

            return Visit(left);
        }

        public override double VisitFunc(testGrammerParser.FuncContext context)
        {
            var type = context.funcname().GetText();

            switch (type)
            {
                case "cos":
                    return Math.Cos(Visit(context.expression()));

                case "sin":
                    return Math.Sin(Visit(context.expression()));

                case "tan":
                    return Math.Tan(Visit(context.expression()));

                case "acos":
                    return Math.Acos(Visit(context.expression()));

                case "asin":
                    return Math.Asin(Visit(context.expression()));

                case "atan":
                    return Math.Atan(Visit(context.expression()));

                case "ln":
                    return Math.Log(Visit(context.expression()));

                case "log":
                    return Math.Log(Visit(context.expression()));
            }

            return Visit(context.expression());
        }

        public override double VisitNumber(testGrammerParser.NumberContext context)
        {
            var left = context.DIGIT(0);
            var right = context.DIGIT(1);
            int minus = 1;

            if (context.MINUS() != null)
            {
                minus = -1;
            }

            if (right != null)
            {
                return (minus * Visit(left)) + Visit(right);
            }

            return minus * Visit(left);
        }

        public override double VisitVariable(testGrammerParser.VariableContext context)
        {
            return base.VisitVariable(context); // yet to implement this
        }

        public override double VisitTerminal(Antlr4.Runtime.Tree.ITerminalNode node)
        {
            return double.Parse(node.GetText());
        }

    }
}

and here is its grammer

grammar testGrammer;

/*
 * Parser Rules
 */

 compileUnit
    :   expression + EOF
    ;

expression
   : multiplyingExpression ((PLUS | MINUS) multiplyingExpression)*
   ;

multiplyingExpression
   : powExpression ((TIMES | DIV) powExpression)*
   ;

powExpression
   : atom (POW atom)*
   ;

atom
   : scientific
   | variable
   | LPAREN expression RPAREN
   | func
   ;

scientific
   : number (E number)?
   ;

func
   : funcname LPAREN expression RPAREN
   ;

funcname
   : COS
   | TAN
   | SIN
   | ACOS
   | ATAN
   | ASIN
   | LOG
   | LN
   ;

number
   : MINUS? DIGIT + (POINT DIGIT +)?
   ;

variable
   : MINUS? LETTER (LETTER | DIGIT)*
   ;

COS
   : 'cos'
   ;

SIN
   : 'sin'
   ;

TAN
   : 'tan'
   ;

ACOS
   : 'acos'
   ;

ASIN
   : 'asin'
   ;

ATAN
   : 'atan'
   ;

LN
   : 'ln'
   ;

LOG
   : 'log'
   ;

LPAREN
   : '('
   ;

RPAREN
   : ')'
   ;

PLUS
   : '+'
   ;

MINUS
   : '-'
   ;

TIMES
   : '*'
   ;

DIV
   : '/'
   ;

POINT
   : '.'
   ;

E
   : 'e' | 'E'
   ;

POW
   : '^'
   ;

LETTER
   : ('a' .. 'z') | ('A' .. 'Z')
   ;

DIGIT
   : ('0' .. '9')
   ;

/*
 * Lexer Rules
 */

WS
    :[ \r\n\t] + -> channel(HIDDEN)
    ;

the main class i used to test it is

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Antlr4.Runtime;
using Antlr4.Runtime.Tree;
using System.Windows.Forms;


namespace ExpressionParser
{
    class Program
    {
        static void Main(string[] args)
        {
            String input = "cos(3*3+3)";

            ITokenSource lexer = new testGrammerLexer(new AntlrInputStream(input));
            ITokenStream tokens = new CommonTokenStream(lexer);
            testGrammerParser parser = new testGrammerParser(tokens);
            parser.AddErrorListener(new ThrowExceptionErrorListener());
            parser.BuildParseTree = true;
            IParseTree tree;

            try
            {
                tree = parser.compileUnit();
                var visitor = new testVisitor();
                var results = visitor.Visit(tree);

                MessageBox.Show(results + "");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
}

#NailedIt

lulliezy
  • 1,204
  • 3
  • 18
  • 36