Irony - 语言实现工具包/语法/非终结符
规则告诉解析器如何将扫描器馈送的标记组合成表达式和语句。
“+”和“|”已被重载,因此您可以将终结符和非终结符串在一起以定义这些规则。
来自 Irony 项目中找到的 ExpressionEvaluatorGrammar 示例
// 2. Non-terminals
var Term = new NonTerminal("Term");
var BinExpr = new NonTerminal("BinExpr", typeof(BinaryOperationNode));
var ParExpr = new NonTerminal("ParExpr");
var UnExpr = new NonTerminal("UnExpr", typeof(UnaryOperationNode));
var UnOp = new NonTerminal("UnOp");
var BinOp = new NonTerminal("BinOp", "operator");
var PrefixIncDec = new NonTerminal("PrefixIncDec", typeof(IncDecNode));
var PostfixIncDec = new NonTerminal("PostfixIncDec", typeof(IncDecNode));
var IncDecOp = new NonTerminal("IncDecOp");
var AssignmentStmt = new NonTerminal("AssignmentStmt", typeof(AssignmentNode));
var AssignmentOp = new NonTerminal("AssignmentOp", "assignment operator");
var Statement = new NonTerminal("Statement");
var Program = new NonTerminal("Program", typeof(StatementListNode));
// 3. BNF rules
Expr.Rule = Term | UnExpr | BinExpr | PrefixIncDec | PostfixIncDec;
Term.Rule = number | ParExpr | identifier | stringLit;
ParExpr.Rule = "(" + Expr + ")";
UnExpr.Rule = UnOp + Term;
UnOp.Rule = ToTerm("+") | "-";
BinExpr.Rule = Expr + BinOp + Expr;
BinOp.Rule = ToTerm("+") | "-" | "*" | "/" | "**";
PrefixIncDec.Rule = IncDecOp + identifier;
PostfixIncDec.Rule = identifier + IncDecOp;
IncDecOp.Rule = ToTerm("++") | "--";
AssignmentStmt.Rule = identifier + AssignmentOp + Expr;
AssignmentOp.Rule = ToTerm("=") | "+=" | "-=" | "*=" | "/=";
Statement.Rule = AssignmentStmt | Expr | Empty;
Program.Rule = MakePlusRule(Program, NewLine, Statement);
在传统的 BNF 表示法中,“?”、“+”和“*”字符分别用于表示“0 次或 1 次”、“1 次或多次”和“0 次或多次”。在 Irony 中,它的实现方式略有不同。您可以使用来自基础 Grammar 类的 MakePlusRule 和 MakeStarRule 方法分别表示“+”和“*”,或者您可以直接在规则中的项上使用 Q()、Plus() 和 Star() 方法。
许多语言都以一个名为“program”的非终结符开始,该非终结符包含一个或多个“statement”非终结符。以下是您指示该方法的方式
Root = program;
program = MakePlusRule(program, statement);
statement = ...
重要说明:当使用 MakePlusRule 或 MakeStarRule 时,规则中不能包含其他任何内容。
PreferShiftHere ReduceHere ResolveInCode ImplyPrecedenceHere
瞬态是非终结符,解析器使用它们将语句分解成更细粒度的表达式,但在其他情况下则不需要。例如,如果您有一个名为“expression”的非终结符,它可以分解成更细粒度的“binaryExpression”,那么通常您只关心它最终被识别为“binaryExpression”。将“expression”放入解析树只会创建一个实际上不需要存在的额外节点。
您可以使用来自基础 Grammar 类的 MarkTransient 方法指示哪些非终结符是瞬态的。
MarkTransient(Term, Expr, Statement, BinOp, UnOp, IncDecOp, AssignmentOp, ParExpr);
您不能标记任何其 AST 节点类型为 StatementListNode 的非终结符为瞬态。因此,像“program”这样的非终结符不能被标记为瞬态,因为它的定义是一系列语句。