ANTLR4をC#から使ってみる #06 Visitorでの計算機の完成
前回まででVisitorの使い方がわかったので、計算機を完成させる。
実装
文法ファイル
Calculator.g4
grammar Calculator;
PLUS : '+';
MINUS: '-';
MULTI: '*';
DIV : '/';
NUMBER : [0-9]+;
WHITESPACE : [ \r\n\t]+ -> skip;
expression
: NUMBER # Number
| '(' inside=expression')' # Parentheses
| left=expression MULTI right=expression # Multiplication
| left=expression DIV right=expression # Division
| left=expression PLUS right=expression # Addition
| left=expression MINUS right=expression # Subtraction
;
grammar Calculator;
PLUS : '+';
MINUS: '-';
MULTI: '*';
DIV : '/';
NUMBER : [0-9]+;
WHITESPACE : [ \r\n\t]+ -> skip;
expression
: NUMBER # Number
| '(' inside=expression')' # Parentheses
| left=expression MULTI right=expression # Multiplication
| left=expression DIV right=expression # Division
| left=expression PLUS right=expression # Addition
| left=expression MINUS right=expression # Subtraction
;
演算(+ - / *)の左辺 右辺を区別するために、Rule Element Labelsという仕組みを使う。
そのため、grammarファイルで演算の左のexpressionをleft,右のexpressionをrightとラベルを付ける。
そのために、grammarファイルに下記のようにleft=,right=を追記する。
またカッコについても大本のexpressionと区別するためinsideのラベルを付ける。
| left=expression MULTI right=expression # Multiplication
Visitorクラス作成
CalculatorBaseVisitorを継承して作成。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Antlr4.Runtime.Misc;
namespace Calculator02_2
{
class CalculatorVisitor: CalculatorBaseVisitor<float>
{
public override float VisitAddition([NotNull] CalculatorParser.AdditionContext context)
{
return base.Visit(context.left) + base.Visit(context.right);
}
public override float VisitDivision([NotNull] CalculatorParser.DivisionContext context)
{
return base.Visit(context.left) / base.Visit(context.right);
}
public override float VisitMultiplication([NotNull] CalculatorParser.MultiplicationContext context)
{
return base.Visit(context.left) * base.Visit(context.right);
}
public override float VisitSubtraction([NotNull] CalculatorParser.SubtractionContext context)
{
return base.Visit(context.left) - base.Visit(context.right);
}
public override float VisitParentheses([NotNull] CalculatorParser.ParenthesesContext context)
{
return base.Visit(context.inside);
}
public override float VisitNumber([NotNull] CalculatorParser.NumberContext context)
{
return float.Parse(context.NUMBER().GetText());
}
}
}
各演算から、左辺/右辺をvisit。数値は数値をそのまま返す。
Program.cs
visitがfloatを返すようになったので、それを表示するように変更。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Antlr4.Runtime;
namespace Calculator02_2
{
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);
var graphContext = parser.expression();
CalculatorVisitor visitor = new CalculatorVisitor();
Console.WriteLine(visitor.Visit(graphContext));
}
}
}
実行結果
>Calculator02_2.exe 3-1
2
>Calculator02_2.exe 3-1*5
-2
>Calculator02_2.exe 3-1*5/2
0.5
>Calculator02_2.exe (3-1)*5/2
5
>Calculator02_2.exe 1*2+3/4
2.75
メモ
>Calculator02_2.exe 3-1
2
>Calculator02_2.exe 3-1*5
-2
>Calculator02_2.exe 3-1*5/2
0.5
>Calculator02_2.exe (3-1)*5/2
5
>Calculator02_2.exe 1*2+3/4
2.75
Visitorから別のVisitorをvisitする際に、base.を付ける必要あるか。
付ける場合と付けない場合の違いはなにか。
後日調べる?
Author And Source
この問題について(ANTLR4をC#から使ってみる #06 Visitorでの計算機の完成), 我々は、より多くの情報をここで見つけました https://qiita.com/Hidenori/items/2c28ab70dc532d99d699著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .