前期知识
编译器基本知识:
编译:将高级语言翻译成汇编语言或者机器语言的过程; 高级语言为源语言,汇编语言为目标语言。
ANTLR简介
官网地址:https://www.antlr.org/
What is ANTLR?
ANTLR (ANother Tool for Language Recognition) is a powerful parser generator for reading, processing, executing, or translating structured text or binary files. It’s widely used to build languages, tools, and frameworks. From a grammar, ANTLR generates a parser that can build and walk parse trees.
ANTLR是开源的语法解析器生成器,距今已有30多年的历史。是一个经历了时间考验的开源项目。一个程序从源代码到机器可执行,基本需要3个阶段:编写、编译、执行。
在编译阶段,需要进行词法和语法的分析。ANTLR聚焦的问题就是把源码进行词法和句法分析,产生一个树状的分析器。ANTLR几乎支持对所有主流编程语言的解析。从antlr/grammars-v4可以看到,ANTLR支持Java,C, Python, SQL等数十种编程语言。通常我们没有扩展编程语言的需求,所以大部分情况下这些语言编译支持更多是供学习研究使用,或者用在各种开发工具(NetBeans、Intellij)中用于校验语法正确性、和格式化代码。
ANTLR实现四则运算例子
- 基于需求按照ANTLR4的规则编写自定义语法的语义规则, 保存成以g4为后缀的文件。
grammar Calculator; //表示文件是一个词法,语法混合的文件。名称必须和文件名字相同
//语法单元以小写字母开发
line: expr EOF;
expr: '(' expr ')' # parenExpr //# 是产生式标签,起到标记不同规则
| expr ('*'|'/') expr # multOrDiv
| expr ('+'|'-') expr # addOrSubtract
| FLOAT # float;
//词法单元以大写字母开头
WS: [ \t\n\r]+ ->skip ; //词法规则 ->skip 是antlr4的特殊命令,表示跳过不做任何处理
FLOAT:DIGIT + '.' DIGIT*EXPONENT?
|'.' DIGIT+EXPONENT?
| DIGIT+EXPONENT? ;
fragment DIGIT : '0'..'9'; // '0'..'9' 表示0~9的字符
fragment EXPONENT :('e'+'E') ('+'+'-')? DIGIT+; //fragment 词片段的问题 不会生成对应的token
- Idea 安装使用ANTLR4工具插件处理g4文件,生成词法分析器、句法分析器代码、词典文件。
! - 实现visitor接口编写对应标签处理逻辑
public class MyCalculatorVisitor extends CalculatorBaseVisitor<Object> {
@Override
public Object visitAddOrSubtract(CalculatorParser.AddOrSubtractContext ctx) {
Object accept = ctx.expr(0).accept(this);
Object accept1 = ctx.expr(1).accept(this);
if ("+".equals(ctx.getChild(1).getText())){
return (Float)accept +(Float)accept1;
}else if ("-".equals(ctx.getChild(1).getText())){
return (Float)accept - (Float)accept1;
}
return 0f;
}
}
- 编写驱动入口类执行
public class Driver {
public static void main(String[] args) {
String query = "1+2";
//对字符串 构造一个ANTLRStrean
ANTLRInputStream input = new ANTLRInputStream(query);
//构造词法解析器 词法解析器 将字符 聚集成单词或者符号
CalculatorLexer calculatorLexer = new CalculatorLexer(input);
// 用词法分析器 构造 一个记号流
CommonTokenStream tokens = new CommonTokenStream(calculatorLexer);
// 再使用 tokens 构造语法分析器 parser,至此已经完成词法分析和语法分析的准备工作
CalculatorParser parser = new CalculatorParser(tokens);
MyCalculatorVisitor myCalculatorVisitor = new MyCalculatorVisitor();
Object accept = parser.expr().accept(myCalculatorVisitor);
System.out.println(accept);
}
}
ANTLR开发语言类应用
设计语法
从编程语言中的范例代码提取语法
- 前期概念
- 编写语法:处理语言规则。ANTLR 会为每条规则生成一个函数。
- 语法由一个该语法命名的头部定义和一系列可以相互引用的语言规则组成。
如何建立初始语法框架?
- 定义: 语言结构辨识从最粗粒度开始,一直进行到最详细层次,并把他们编写称为语法规则。
- 步骤
- 编写伪代码
1. 找到最粗粒度的语言结构作为起始规则。
2. 设计起始规则内容就是 使用 “英语伪代码” 来描述输入的文本结构。例子:一个CSV文件就是一系列以换行符为终止的行( a comma-separated-value[CSV] is a sequence of rows terminated by newlines);
3. 下一层级,描述起始规则右侧所指定的那些元素( sequence of rows terminated by newlines)。由词法符号或者未定义的规则组成
- 定义:
- 词法符号:大脑能够轻易识别的出的单词,标点符号或者运算符。
- 规则: row is a sequence of fields sparated by commas
4. 再降低层: a field is number or string
grammar Mg; //伪代码
file: <<sequence of rows terminated by newlines>> //
row:<< a row is a sequence of fields sparated by commas >>
field: <<a field is number or string >>
- 将伪代码翻译为ANTLR 标记,得到正常工作语法
- 基本概念:语言模式
- 序列模式:由 指令(关键字)、一个操作数和一个换行符构成。
- 选择模式:使用 | 符号表达编程语言中的选择模式
- 词法符号依赖模式
- 嵌套模式:嵌套词组是一种自相似的语言结构,即它子词组遵循相同的结构
- 基本概念:语言模式
grammar Mg; //伪代码
//+字符处理一个或多个的情况。
//*字符处理零个或多个的情况。
//特殊的零个或者一个元素的序列 , (‘=’expr)?,在有无之间选择
file: (row '\n')* ;// 以\n为终止符的 序列
row: field (',' field)* ; // 以‘,’为分隔符的 序列
field: INT|STRING; // 字段可以为整数或者字符串 通过| 选择模式
vector: '[' INT+ ']' // [1] [2 3] 词法符号依赖模式
stat: 'while' '(' expr ')' stat //匹配WHILE语句
| '{' stat* '}' //匹配花括号中若干条语句 嵌套模式
- 识别常见的语法结构
ANTLR 文件允许词法规则和语法规则放入一个文件。词法文件以大写字母开头,文法文件以小写字母开头。
展示词法规则:- 匹配标识符
ID:( ‘a’… ‘z’)|(‘A’…‘Z’)+ //匹配一个或多个大小写字母
ID:[a-zA-Z]+ ; 匹配一个或多个大小写字母