前回の記事までで、下記がわかった。
- C#でANTLR4を利用するためのVisual Studioの設定方法と、プロジェクトを作った後の設定方法
- ListenerのではExit***の挙動
- Exit***リスナーとスタックを使うとListenerで計算機を作れること
実装
Listenerクラスへのスタックの作り込み
Stack<float> stack = new Stack<float>();
演算子(+-*/)の実装
public override void ExitAddition([NotNull] CalculatorParser.AdditionContext context)
{
base.ExitAddition(context);
stack.Push(stack.Pop() + stack.Pop());
}
public override void ExitDivision([NotNull] CalculatorParser.DivisionContext context)
{
base.ExitDivision(context);
var right = stack.Pop();
var left = stack.Pop();
stack.Push(left / right);
}
・・・
スタックからの計算結果の取り出し用のメソッド作成
public float getAnswer()
{
return stack.Pop();
}
mainメソッドからの計算結果の取り出しと出力
Console.WriteLine(listener.getAnswer());
実行結果
>Calculator01_3.exe 3-1
2
>Calculator01_3.exe 3-1*5
-2
>Calculator01_3.exe 3-1*5/2
0.5
>Calculator01_3.exe (3-1)*5/2
5
>Calculator01_3.exe 1*2+3/4
2.75
最終的なソース
Calculator.g4
grammar Calculator;
PLUS : '+';
MINUS: '-';
MULTI: '*';
DIV : '/';
NUMBER : [0-9]+;
WHITESPACE : [ \r\n\t]+ -> skip;
expression
: NUMBER # Number
| '(' expression ')' # Parentheses
| expression MULTI expression # Multiplication
| expression DIV expression # Division
| expression PLUS expression # Addition
| expression MINUS expression # Subtraction
;
Program.cs
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;usingAntlr4.Runtime;namespaceCalculator01_3{classProgram{staticvoidMain(string[]args){stringparsedString;if(args.Length==0){Console.WriteLine("引数に数式を指定してください");return;}else{parsedString=args[0];}varinputStream=newAntlrInputStream(parsedString);varlexer=newCalculatorLexer(inputStream);varcommonTokenStream=newCommonTokenStream(lexer);varparser=newCalculatorParser(commonTokenStream);CalculatorListenerlistener=newCalculatorListener();parser.AddParseListener(listener);vargraphContext=parser.expression();Console.WriteLine(listener.getAnswer());}}}CalculatorListener.cs
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;usingAntlr4.Runtime.Misc;namespaceCalculator01_3{classCalculatorListener:CalculatorBaseListener{Stack<float>stack=newStack<float>();publicoverridevoidExitNumber([NotNull]CalculatorParser.NumberContextcontext){base.ExitNumber(context);stack.Push(float.Parse(context.NUMBER().GetText()));}publicoverridevoidExitAddition([NotNull]CalculatorParser.AdditionContextcontext){base.ExitAddition(context);stack.Push(stack.Pop()+stack.Pop());}publicoverridevoidExitDivision([NotNull]CalculatorParser.DivisionContextcontext){base.ExitDivision(context);varright=stack.Pop();varleft=stack.Pop();stack.Push(left/right);}publicoverridevoidExitMultiplication([NotNull]CalculatorParser.MultiplicationContextcontext){base.ExitMultiplication(context);stack.Push(stack.Pop()*stack.Pop());}publicoverridevoidExitSubtraction([NotNull]CalculatorParser.SubtractionContextcontext){base.ExitSubtraction(context);varright=stack.Pop();varleft=stack.Pop();stack.Push(left-right);}publicfloatgetAnswer(){returnstack.Pop();}}}