编译原理

stateDiagram-v2
  源代码 --> 词法分析
  state 前端 {
    词法分析 --> 语法分析
    语法分析 --> 语义分析
  }
  语义分析 --> 生成中间代码
  state 后端 {
    生成中间代码 --> 优化
    优化 --> 生成目标代码
  }

词法分析

有限自动机

要实现一个词法分析器,首先需要写出每个词法的正则表达式,并画出有限自动机,之后,只要用代码表示这种状态迁移过程就可以了

age >= 45 的此法解析自动机:

stateDiagram-v2
  初始 --> 比较操作符>: >
  比较操作符> --> 比较操作符>=: =
  初始 --> ID: 字母
  ID --> ID: 字母或数字
  初始 --> 数字字面量: 数字
  数字字面量 --> 数字字面量: 数字
DfaState newState = DfaState.Initial;
if (isAlpha(ch)) {              //第一个字符是字母
    newState = DfaState.Id; //进入Id状态
    token.type = TokenType.Identifier;
    tokenText.append(ch);
} else if (isDigit(ch)) {       //第一个字符是数字
    newState = DfaState.IntLiteral;
    token.type = TokenType.IntLiteral;
    tokenText.append(ch);
} else if (ch == '>') {         //第一个字符是>
    newState = DfaState.GT;
    token.type = TokenType.GT;
    tokenText.append(ch);
}

使用正则表达式描述词法:

Id :        [a-zA-Z_] ([a-zA-Z_] | [0-9])*
IntLiteral: [0-9]+
GT :        '>'
GE :        '>='

语法分析

语法规则描述

BNF:

add ::= mul | add + mul
mul ::= pri | mul * pri
pri ::= Id | Num | (add) 

扩展BNF(EBNF):

// 会用到类似正则表达式的一些写法
add -> mul (+ mul)*

上下文无关文法

上下文无关指的是无论在任何情况下,文法的推导规则都是一样的

描述整数加法与乘法的文法,在解析后,可以形成一颗AST:

additiveExpression
    :   multiplicativeExpression
    |   additiveExpression Plus multiplicativeExpression
    ;

multiplicativeExpression
    :   IntLiteral
    |   multiplicativeExpression Star IntLiteral
    ;

“2+3*5” 的推导过程:

-->additiveExpression + multiplicativeExpression
-->multiplicativeExpression + multiplicativeExpression
-->IntLiteral + multiplicativeExpression
-->IntLiteral + multiplicativeExpression * IntLiteral 
-->IntLiteral + IntLiteral * IntLiteral

递归下降

上级文法嵌套下级文法,上级的算法调用下级的算法

消除左递归:

对于加法与乘法的文法:

add -> mul | add + mul   

会陷入无限递归,那就引入一个终止条件,也就是空集来终止递归:

add -> mul add'
add' -> + mul add' | ε
// EBNP表达
add -> mul (+ mul)* 

Antlr

词法规则文件:

lexer grammar Hello;  //lexer关键字意味着这是一个词法规则文件,要与文件名相同。

@header {
package antlrtest;
}

//关键字
If :               'if' | '如果';   //可以在程序里用‘如果’来代替'if'
Int :              'int';

//常量
IntLiteral:        [0-9]+;
StringLiteral:      '"' .*? '"' ;  //字符串常量

//操作符
AssignmentOP:       '=' ;    
RelationalOP:       '=='|'>'|'>='|'<' |'<=' ;    
Star:               '*';
Plus:               '+';
Sharp:              '#';
SemiColon:          ';';
Dot:                '.';
Comm:               ',';
LeftBracket :       '[';
RightBracket:       ']';
LeftBrace:          '{';
RightBrace:         '}';
LeftParen:          '(';
RightParen:         ')';

//标识符
Id :                [a-zA-Z_] ([a-zA-Z_] | [0-9])*;

//空白字符,抛弃
Whitespace:         [ \t]+ -> skip;
Newline:            ( '\r' '\n'?|'\n')-> skip;
// 语法分析器
expression
    :   assignmentExpression
    |   expression ',' assignmentExpression
    ;

assignmentExpression
    :   additiveExpression
    |   Identifier assignmentOperator additiveExpression
    ;

assignmentOperator
    :   '='
    |   '*='
    |  '/='
    |   '%='
    |   '+='
    |   '-='
    ;

additiveExpression
    :   multiplicativeExpression
    |   additiveExpression '+' multiplicativeExpression
    |   additiveExpression '-' multiplicativeExpression
    ;

multiplicativeExpression
    :   primaryExpression
    |   multiplicativeExpression '*' primaryExpression
    |   multiplicativeExpression '/' primaryExpression
    |   multiplicativeExpression '%' primaryExpression
    ;
# 生成词法分析器的java源码
antlr Hello.g4
# 生成语法分析器
antlr PlayScript.g4
# 输入表达式查看AST
grun antlrtest.PlayScript expression -gui