前回の記事までで、下記がわかった。
- 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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Antlr4.Runtime;
namespace Calculator01_3
{
class Program
{
static void Main(string[] args)
{
string parsedString;
if (args.Length == 0)
{
Console.WriteLine("引数に数式を指定してください");
return;
}
else
{
parsedString = args[0];
}
var inputStream = new AntlrInputStream(parsedString);
var lexer = new CalculatorLexer(inputStream);
var commonTokenStream = new CommonTokenStream(lexer);
var parser = new CalculatorParser(commonTokenStream);
CalculatorListener listener = new CalculatorListener();
parser.AddParseListener(listener);
var graphContext = parser.expression();
Console.WriteLine(listener.getAnswer());
}
}
}
CalculatorListener.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Antlr4.Runtime.Misc;
namespace Calculator01_3
{
class CalculatorListener : CalculatorBaseListener
{
Stack<float> stack = new Stack<float>();
public override void ExitNumber([NotNull] CalculatorParser.NumberContext context)
{
base.ExitNumber(context);
stack.Push(float.Parse(context.NUMBER().GetText()));
}
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 override void ExitMultiplication([NotNull] CalculatorParser.MultiplicationContext context)
{
base.ExitMultiplication(context);
stack.Push(stack.Pop() * stack.Pop());
}
public override void ExitSubtraction([NotNull] CalculatorParser.SubtractionContext context)
{
base.ExitSubtraction(context);
var right = stack.Pop();
var left = stack.Pop();
stack.Push(left - right);
}
public float getAnswer()
{
return stack.Pop();
}
}
}