好的!现在让我们将前面所有步骤整合成一个完整的、可运行的例子。我们将创建一个简单的计算器语言,支持变量、基本运算和函数调用。
完整示例:SimpleCalc 语言
文件结构
SimpleCalc/
├── src/
│ └── main/
│ └── antlr/
│ └── SimpleCalc.g4 # 语法定义文件
├── examples/
│ ├── example1.scalc # 示例程序1
│ └── example2.scalc # 示例程序2
└── README.md第一步:语法文件骨架
文件:SimpleCalc.g4
/*
* SimpleCalc 语言语法定义
* 一个简单的计算器语言,支持变量、函数和基本运算
*/
// 第一步:grammar 声明
grammar SimpleCalc;第二步:添加 @header 动作
grammar SimpleCalc;
// 第二步:@header 动作 - 定义包结构和导入
@header {
package com.example.simplecalc.parser;
import java.util.Map;
import java.util.HashMap;
import java.math.BigDecimal;
}第三步:定义词法规则(Lexer Rules)
// 第三步:词法规则 - 定义语言的基本单词
// === 关键字 ===
VAR : 'var' ;
FUNC : 'func' ;
IF : 'if' ;
ELSE : 'else' ;
WHILE : 'while' ;
RETURN : 'return' ;
PRINT : 'print' ;
// === 类型关键字 ===
INT_TYPE : 'int' ;
FLOAT_TYPE : 'float' ;
BOOL_TYPE : 'bool' ;
STRING_TYPE : 'string' ;
// === 字面量 ===
fragment DIGIT : [0-9] ;
fragment LETTER : [a-zA-Z_] ;
fragment ESCAPE : '\\' [btnfr"\\] ; // 转义字符: \b, \t, \n, \f, \r, \", \\
INT_LITERAL : DIGIT+ ;
FLOAT_LITERAL : DIGIT+ '.' DIGIT*
| '.' DIGIT+
;
BOOL_LITERAL : 'true' | 'false' ;
STRING_LITERAL : '"' (ESCAPE | ~["\\])* '"' ;
NULL_LITERAL : 'null' ;
// === 标识符 ===
IDENTIFIER : LETTER (LETTER | DIGIT)* ;
// === 运算符 ===
// 赋值
ASSIGN : '=' ;
// 算术运算符
PLUS : '+' ;
MINUS : '-' ;
MUL : '*' ;
DIV : '/' ;
MOD : '%' ;
POW : '**' ;
// 比较运算符
EQ : '==' ;
NEQ : '!=' ;
LT : '<' ;
GT : '>' ;
LTE : '<=' ;
GTE : '>=' ;
// 逻辑运算符
AND : '&&' ;
OR : '||' ;
NOT : '!' ;
// === 分隔符 ===
LPAREN : '(' ;
RPAREN : ')' ;
LBRACE : '{' ;
RBRACE : '}' ;
LBRACKET : '[' ;
RBRACKET : ']' ;
SEMI : ';' ;
COMMA : ',' ;
DOT : '.' ;
COLON : ':' ;
QUESTION : '?' ;
// === 需要跳过的内容 ===
WS : [ \t\r\n]+ -> skip ; // 空白字符
LINE_COMMENT: '//' ~[\r\n]* -> skip ; // 单行注释
BLOCK_COMMENT: '/*' .*? '*/' -> skip ; // 多行注释第四步:定义语法规则(Parser Rules)
// 第四步:语法规则 - 定义语言结构
// === 程序结构 ===
program : (functionDecl | statement)+ EOF ;
// === 函数声明 ===
functionDecl : FUNC IDENTIFIER LPAREN parameterList? RPAREN
(COLON type)? block ;
parameterList : parameter (COMMA parameter)* ;
parameter : IDENTIFIER COLON type ;
type : INT_TYPE | FLOAT_TYPE | BOOL_TYPE | STRING_TYPE ;
// === 语句(Statements)===
statement
: variableDecl SEMI # VariableDeclStmt
| assignment SEMI # AssignmentStmt
| ifStatement # IfStmt
| whileStatement # WhileStmt
| returnStatement SEMI # ReturnStmt
| printStatement SEMI # PrintStmt
| expression SEMI # ExpressionStmt
| block # BlockStmt
| SEMI # EmptyStmt
;
variableDecl : VAR IDENTIFIER (COLON type)? (ASSIGN expression)? ;
assignment : IDENTIFIER ASSIGN expression ;
returnStatement : RETURN expression? ;
printStatement : PRINT expression ;
// === 控制流语句 ===
ifStatement : IF LPAREN expression RPAREN statement (ELSE statement)? ;
whileStatement : WHILE LPAREN expression RPAREN statement ;
block : LBRACE statement* RBRACE ;
// === 表达式(Expressions)- 优先级处理 ===
// 第五步:处理递归和优先级
expression
: assignmentExpression
;
assignmentExpression
: IDENTIFIER ASSIGN assignmentExpression # AssignmentExpr
| conditionalExpression # ConditionalExpr
;
conditionalExpression
: logicalOrExpression (QUESTION expression COLON conditionalExpression)?
;
logicalOrExpression
: logicalAndExpression (OR logicalAndExpression)*
;
logicalAndExpression
: equalityExpression (AND equalityExpression)*
;
equalityExpression
: relationalExpression ((EQ | NEQ) relationalExpression)*
;
relationalExpression
: additiveExpression ((LT | GT | LTE | GTE) additiveExpression)*
;
additiveExpression
: multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)*
;
multiplicativeExpression
: powerExpression ((MUL | DIV | MOD) powerExpression)*
;
powerExpression
: unaryExpression (POW unaryExpression)*
;
unaryExpression
: (PLUS | MINUS | NOT) unaryExpression # UnaryExpr
| postfixExpression # PostfixExpr
;
postfixExpression
: primaryExpression
| postfixExpression LPAREN argumentList? RPAREN # FunctionCall
| postfixExpression LBRACKET expression RBRACKET # ArrayAccess
| postfixExpression DOT IDENTIFIER # MemberAccess
;
primaryExpression
: literal # LiteralExpr
| IDENTIFIER # VariableExpr
| LPAREN expression RPAREN # ParenthesizedExpr
| arrayLiteral # ArrayLiteralExpr
;
// === 字面量和数据结构 ===
literal
: INT_LITERAL # IntLiteral
| FLOAT_LITERAL # FloatLiteral
| BOOL_LITERAL # BoolLiteral
| STRING_LITERAL # StringLiteral
| NULL_LITERAL # NullLiteral
;
arrayLiteral : LBRACKET (expression (COMMA expression)*)? RBRACKET ;
argumentList : expression (COMMA expression)* ;完整的 SimpleCalc.g4 文件
将以上所有部分组合起来:
/*
* SimpleCalc 语言语法定义
* 一个简单的计算器语言,支持变量、函数和基本运算
*/
// 第一步:grammar 声明
grammar SimpleCalc;
// 第二步:@header 动作
@header {
package com.example.simplecalc.parser;
import java.util.Map;
import java.util.HashMap;
import java.math.BigDecimal;
}
// 第三步:词法规则
VAR : 'var' ;
FUNC : 'func' ;
IF : 'if' ;
ELSE : 'else' ;
WHILE : 'while' ;
RETURN : 'return' ;
PRINT : 'print' ;
INT_TYPE : 'int' ;
FLOAT_TYPE : 'float' ;
BOOL_TYPE : 'bool' ;
STRING_TYPE : 'string' ;
fragment DIGIT : [0-9] ;
fragment LETTER : [a-zA-Z_] ;
fragment ESCAPE : '\\' [btnfr"\\] ;
INT_LITERAL : DIGIT+ ;
FLOAT_LITERAL : DIGIT+ '.' DIGIT* | '.' DIGIT+ ;
BOOL_LITERAL : 'true' | 'false' ;
STRING_LITERAL : '"' (ESCAPE | ~["\\])* '"' ;
NULL_LITERAL : 'null' ;
IDENTIFIER : LETTER (LETTER | DIGIT)* ;
ASSIGN : '=' ;
PLUS : '+' ; MINUS : '-' ; MUL : '*' ; DIV : '/' ; MOD : '%' ; POW : '**' ;
EQ : '==' ; NEQ : '!=' ; LT : '<' ; GT : '>' ; LTE : '<=' ; GTE : '>=' ;
AND : '&&' ; OR : '||' ; NOT : '!' ;
LPAREN : '(' ; RPAREN : ')' ; LBRACE : '{' ; RBRACE : '}' ;
LBRACKET : '[' ; RBRACKET : ']' ; SEMI : ';' ; COMMA : ',' ;
DOT : '.' ; COLON : ':' ; QUESTION : '?' ;
WS : [ \t\r\n]+ -> skip ;
LINE_COMMENT: '//' ~[\r\n]* -> skip ;
BLOCK_COMMENT: '/*' .*? '*/' -> skip ;
// 第四步 + 第五步:语法规则与优先级处理
program : (functionDecl | statement)+ EOF ;
functionDecl : FUNC IDENTIFIER LPAREN parameterList? RPAREN (COLON type)? block ;
parameterList : parameter (COMMA parameter)* ;
parameter : IDENTIFIER COLON type ;
type : INT_TYPE | FLOAT_TYPE | BOOL_TYPE | STRING_TYPE ;
statement
: variableDecl SEMI | assignment SEMI | ifStatement | whileStatement
| returnStatement SEMI | printStatement SEMI | expression SEMI
| block | SEMI
;
variableDecl : VAR IDENTIFIER (COLON type)? (ASSIGN expression)? ;
assignment : IDENTIFIER ASSIGN expression ;
returnStatement : RETURN expression? ;
printStatement : PRINT expression ;
ifStatement : IF LPAREN expression RPAREN statement (ELSE statement)? ;
whileStatement : WHILE LPAREN expression RPAREN statement ;
block : LBRACE statement* RBRACE ;
expression : assignmentExpression ;
assignmentExpression : IDENTIFIER ASSIGN assignmentExpression | conditionalExpression ;
conditionalExpression : logicalOrExpression (QUESTION expression COLON conditionalExpression)? ;
logicalOrExpression : logicalAndExpression (OR logicalAndExpression)* ;
logicalAndExpression : equalityExpression (AND equalityExpression)* ;
equalityExpression : relationalExpression ((EQ | NEQ) relationalExpression)* ;
relationalExpression : additiveExpression ((LT | GT | LTE | GTE) additiveExpression)* ;
additiveExpression : multiplicativeExpression ((PLUS | MINUS) multiplicativeExpression)* ;
multiplicativeExpression : powerExpression ((MUL | DIV | MOD) powerExpression)* ;
powerExpression : unaryExpression (POW unaryExpression)* ;
unaryExpression : (PLUS | MINUS | NOT) unaryExpression | postfixExpression ;
postfixExpression : primaryExpression | postfixExpression LPAREN argumentList? RPAREN | postfixExpression LBRACKET expression RBRACKET | postfixExpression DOT IDENTIFIER ;
primaryExpression : literal | IDENTIFIER | LPAREN expression RPAREN | arrayLiteral ;
literal : INT_LITERAL | FLOAT_LITERAL | BOOL_LITERAL | STRING_LITERAL | NULL_LITERAL ;
arrayLiteral : LBRACKET (expression (COMMA expression)*)? RBRACKET ;
argumentList : expression (COMMA expression)* ;示例程序
examples/example1.scalc:
// 简单计算器示例
var x = 10;
var y = 20;
var result = x * y + 5;
print(result);
// 条件语句
if (result > 100) {
print("结果大于100");
} else {
print("结果小于等于100");
}
// 循环示例
var i = 0;
while (i < 5) {
print(i);
i = i + 1;
}examples/example2.scalc:
// 函数定义和调用示例
func factorial(n: int): int {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
func main() {
var num = 5;
var fact = factorial(num);
print("阶乘结果: " + fact);
}
main();编译和测试步骤
1. 生成解析器代码
antlr4 SimpleCalc.g42. 编译Java文件
javac -cp "antlr-4.9.3-complete.jar" SimpleCalc*.java3. 测试语法解析
# 测试示例1
grun SimpleCalc program -tree examples/example1.scalc
grun SimpleCalc program -gui examples/example1.scalc
# 测试示例2
grun SimpleCalc program -tree examples/example2.scalc关键特性总结
这个完整的例子展示了:
✅ 第一步完成:正确的 grammar 声明
✅ 第二步完成:合理的包结构定义
✅ 第三步完成:完整的词法规则,包含:
- 关键字和标识符
- 各种字面量类型
- 运算符和分隔符
- 空白和注释处理
✅ 第四步完成:层次化的语法规则,包含:
- 程序结构(函数和语句)
- 各种语句类型(声明、赋值、控制流)
- 表达式层次结构
✅ 第五步完成:正确的优先级处理:
- 15级优先级层次(从赋值到底层表达式)
- 正确的左结合和右结合
- 括号优先级处理
这个完整的语法文件可以直接用于生成功能完整的解析器,能够解析一个具有实用性的简单编程语言。
本文由 jxxxy 创作,采用 知识共享署名4.0 国际许可协议进行许可。
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。