语法分析的结果是生成 AST。算法分为自顶向下和自底向上算法,其中,递归下降算法是一种常见的自顶向下算法。
“int age = 45”这个语句,语法分析算法的示意图:
终结符都是词法分析中产生的 Token。而那些非叶子节点,就是非终结符。
intDeclaration : Int Identifier (’=’ additiveExpression)?;
- SimpleASTNode node = null;
- Token token = tokens.peek(); // 预读
- if (token != null && token.getType() == TokenType.Int) { // 匹配 Int
- token = tokens.read(); // 消耗掉 int
- if (tokens.peek().getType() == TokenType.Identifier) { // 匹配标识符
- token = tokens.read(); // 消耗掉标识符
- // 创建当前节点,并把变量名记到 AST 节点的文本值中,
- // 这里新建一个变量子节点也是可以的
- node = new SimpleASTNode(ASTNodeType.IntDeclaration, token.getText());
- token = tokens.peek(); // 预读
- if (token != null && token.getType() == TokenType.Assignment) {
- tokens.read(); // 消耗掉等号
- SimpleASTNode child = additive(tokens); // 匹配一个表达式
- if (child == null) {
- throw new Exception("invalide variable initialization, expecting an expression");
- }
- else{
- node.addChild(child);
- }
- }
- } else {
- throw new Exception("variable name expected");
- }
- }
-
通常会对产生式的每个部分建立一个子节点,比如变量声明语句会建立四个子节点,分别是 int 关键字、标识符、等号和表达式。
语法规则
- additiveExpression
- : multiplicativeExpression
- | multiplicativeExpression Plus additiveExpression
- ;
-
- 上面的表达式是语法规则,是用BNF表达的。以addtive为例,它有两个产生式。
- 产生式1:一个乘法表达式
- 产生式2:一个加法表达式 + 乘法表达式。
- 通过上面两个产生式的组合,特别是产生式2的递归调用,就能推导出所有的加减乘数算术表达式。
- 比如,对于2*3这个表达式,运用的是产生式1。
- 对于2+3*5,运用的是产生式2。
- 我上面用的语法规则的写法,实际上是后面会用到的Antlr工具的写法。你也可以这样书写,就是一般教材上的写法:
- A -> M | A + M
- M -> int | M * int
- 我们每个非终结符只用了一个大写字母代表,比较简洁。
- 其中的竖线,是选择其一。你还可以拆成最简单的方式,形成4条规则:
- A -> M
- A -> A + M
- M -> int
- M -> M * int
- 上面这些不同的写法,都是等价的。
-