在为我的antlr程序编写访问者时遇到困难,表达式为
multiplyingExpression ((PLUS | MINUS) multiplyingExpression)*
我想得到表达式的左侧部分,获取运算符类型和表达式的右侧部分,请帮助。这就是我到目前为止所拥有的
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));
}
,我得到的错误是Object reference not set to an instance of an object
。
提前致谢。
修改
我更喜欢这样的事情
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
}
编辑2(语法)
这是使用
的语法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)
;
答案 0 :(得分:3)
我终于做到了,这是完整的访客类
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());
}
}
}
这是它的语法
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)
;
我用来测试它的主要类是
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