Antlr3.Runtime.dll)language = CSharp2;System.out.println → Console.WriteLinetoStringTree → ToStringTreeclear → ClearAntlr3.Runtime.dll + Antlr3.Utility.dll + StringTemplate.dllANTLR 以深度優先遍歷 AST,可視為一維 Token 流:
ROOT → DOWN → child1 → child2 → ... → UP → ...
Tree Grammar 中的 ^( ... ) 隱含 DOWN/UP。Lookahead 數直接影響生成代碼複雜度(每多一層巢狀 if-else)。
// Tree Grammar 需 3 步 lookahead 區分分支
type : ^(SIMPLE_TYPE INT) | ^(SIMPLE_TYPE REAL) | ^(ARRAY_TYPE INT Integer+) | ^(ARRAY_TYPE REAL Integer+);
tokens {
SIMPLE_VAR_DECL; SIMPLE_VAR_DECL_INIT;
ARRAY_VAR_DECL; ARRAY_VAR_DECL_INIT;
// ...
}
重寫規則範例:
variableDeclaration
: typeSpecifier
( id1=Identifier
( -> ^(SIMPLE_VAR_DECL[$id1, "VarDecl"] ^(typeSpecifier) $id1)
| EQ expression -> ^(SIMPLE_VAR_DECL_INIT[$id1, "VarDeclInit"] ^(typeSpecifier) $id1 expression)
| (LBRACK Integer RBRACK)+ -> ^(ARRAY_VAR_DECL[$id1, "VarDecl"] ^(typeSpecifier Integer+) $id1)
| (LBRACK Integer RBRACK)+ EQ arrayLiteral -> ^(ARRAY_VAR_DECL_INIT[$id1, "VarDeclInit"] ^(typeSpecifier Integer+) $id1 arrayLiteral)
)
)
( COMMA id2=Identifier
( -> $variableDeclaration ^(SIMPLE_VAR_DECL[$id2, "VarDecl"] ^(typeSpecifier) $id2)
| EQ exp=expression -> $variableDeclaration ^(SIMPLE_VAR_DECL_INIT[$id2, "VarDeclInit"] ^(typeSpecifier) $id2 $exp)
| (LBRACK dim1+=Integer RBRACK)+ -> $variableDeclaration ^(ARRAY_VAR_DECL[$id2, "VarDecl"] ^(typeSpecifier $dim1+) $id2)
| (LBRACK dim2+=Integer RBRACK)+ EQ al=arrayLiteral -> $variableDeclaration ^(ARRAY_VAR_DECL_INIT[$id2, "VarDeclInit"] ^(typeSpecifier $dim2+) $id2 $al)
)
{ if ($dim1!=null) $dim1.Clear(); if ($dim2!=null) $dim2.Clear(); }
)*
SEMICOLON
;
simpleType : INT | REAL; // 1 lookahead
arrayType : ^(INT Integer+) | ^(REAL Integer+); // 1 lookahead
原寫法丟失位置:
MINUS primaryExpression -> ^(UNARY_MINUS primaryExpression)
改為繼承來源 Token 屬性:
MINUS primaryExpression -> ^(UNARY_MINUS[$MINUS] primaryExpression)
後續錯誤報告、IDE 高亮可精準定位至原始碼位置。
grammar Jerry;
options { language = CSharp2; output = AST; ASTLabelType = CommonTree; }
tokens {
SIMPLE_VAR_DECL; SIMPLE_VAR_DECL_INIT; ARRAY_VAR_DECL; ARRAY_VAR_DECL_INIT;
ARRAY_LITERAL; SIMPLE_VAR_ACCESS; ARRAY_VAR_ACCESS; UNARY_MINUS;
BLOCK; EMPTY_BLOCK; EXPR_STMT;
}
// parser rules ... (詳見原文完整列表)
// lexer rules ... (標準運算子、關鍵字、識別字、常數、空白、註解)
using System; using System.IO;
using Antlr.Runtime; using Antlr.Runtime.Tree; using Antlr.Utility.Tree;
sealed class TestJerryAst {
static void Main(string[] args) {
bool genDot = false; string srcFile;
// 參數解析 -dot srcFile
var input = new ANTLRReaderStream(File.OpenText(srcFile));
var lexer = new JerryLexer(input);
var tokens = new CommonTokenStream(lexer);
var parser = new JerryParser(tokens);
var ast = (CommonTree) parser.program().Tree;
if (genDot) {
var dotgen = new DOTTreeGenerator();
Console.WriteLine(dotgen.ToDOT(ast));
} else {
Console.WriteLine(ast.ToStringTree());
}
}
}
輸入 Jerry 代碼:
int i = 1, j;
int x = i + 2 * 3 - 4 / (6 - -7);
int arr[2][3] = {{0,1,2},{3,4,6}};
while (i < 10) i = i + 1;
while (!x > 0 && i < 10) { x = x - 1; if (i < 5) break; else read i; }
write x - j;
生成 AST (DOT → Graphviz PNG):

var, function)使 LL(1) 解析成為可能;C 風格聲明(類型在前、修飾在後)天然需要更多 Lookahead。下一篇將展示針對此 AST 的 Tree Grammar 實作,完成語義分析與解譯器/編譯器前端構建。