ANTLR™ ( AN other T ool for L anguage R ecognition) 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.
可以通过断言(Predicate)解决识别冲突
支持动作(Action)和返回值(Return Value)
它可以根据输入自动生成语法树,并可视化的展示出来
复杂情况下,需要基于语法树遍历(walking the tree)生成目标代码
Embeded action 将处理代码跟语法描述混合起来,语法复杂时使语法文件臃肿
语法可能经常需要修改,而语法的主要表达式却不会变动,因此,Antlr 将语法识别与转换、生成(目标代码)的处理分离
分析量化字符流,翻译成离散的字符组(也就是一堆 Token), 包括关键字,标识符,符号(symbols)和操作符,以供语法分析器使用
将 Tokens 组织起来,并转换成为目标语言语法(默认是Java)定义所允许的序列
用于对语法分析生成的抽象语法树进行遍历,并在先序经过每个树节点的时候,进行一些定制操作
# Download $ cd /usr/local/lib $ curl -O https://www.antlr.org/download/antlr-4.7.2-complete.jar # Add antlr-4.7.2-complete.jar to your CLASSPATH # Create aliases for the ANTLR Tool, and TestRig $ vim ~/.bashrc export CLASSPATH=".:/usr/local/lib/antlr-4.7.2-complete.jar:$CLASSPATH" alias antlr4='java -Xmx500M -cp "/usr/local/lib/antlr-4.7.2-complete.jar:$CLASSPATH" org.antlr.v4.Tool' alias grun='java -Xmx500M -cp "/usr/local/lib/antlr-4.7.2-complete.jar:$CLASSPATH" org.antlr.v4.gui.TestRig' $ source ~/.bashrc
$ vim Benedict.g4 // Define a grammar called Benedict grammar Benedict; r : 'hello' Name ; // match keyword hello followed by an identifier Name : [a-z]+ ; // match lower-case identifiers WS : [ /t/r/n]+ -> skip ; // skip spaces, tabs, newlines
$ antlr4 Benedict.g4 $ ll total 36K -rw-r--r-- 1 benedictjin wheel 93 1 15 14:47 Benedict.g4 -rw-r--r-- 1 benedictjin wheel 321 1 15 14:47 Benedict.interp -rw-r--r-- 1 benedictjin wheel 38 1 15 14:47 Benedict.tokens -rw-r--r-- 1 benedictjin wheel 1.3K 1 15 14:47 BenedictBaseListener.java -rw-r--r-- 1 benedictjin wheel 1.3K 1 15 14:47 BenedictLexer.interp -rw-r--r-- 1 benedictjin wheel 3.7K 1 15 14:47 BenedictLexer.java -rw-r--r-- 1 benedictjin wheel 38 1 15 14:47 BenedictLexer.tokens -rw-r--r-- 1 benedictjin wheel 569 1 15 14:47 BenedictListener.java -rw-r--r-- 1 benedictjin wheel 3.9K 1 15 14:47 BenedictParser.java
$ javac Benedict*.java $ ll total 60K -rw-r--r-- 1 benedictjin wheel 93 1 15 14:47 Benedict.g4 -rw-r--r-- 1 benedictjin wheel 321 1 15 14:47 Benedict.interp -rw-r--r-- 1 benedictjin wheel 38 1 15 14:47 Benedict.tokens -rw-r--r-- 1 benedictjin wheel 822 1 15 14:48 BenedictBaseListener.class -rw-r--r-- 1 benedictjin wheel 1.3K 1 15 14:47 BenedictBaseListener.java -rw-r--r-- 1 benedictjin wheel 3.8K 1 15 14:48 BenedictLexer.class -rw-r--r-- 1 benedictjin wheel 1.3K 1 15 14:47 BenedictLexer.interp -rw-r--r-- 1 benedictjin wheel 3.7K 1 15 14:47 BenedictLexer.java -rw-r--r-- 1 benedictjin wheel 38 1 15 14:47 BenedictLexer.tokens -rw-r--r-- 1 benedictjin wheel 329 1 15 14:48 BenedictListener.class -rw-r--r-- 1 benedictjin wheel 569 1 15 14:47 BenedictListener.java -rw-r--r-- 1 benedictjin wheel 896 1 15 14:48 'BenedictParser$SayContext.class' -rw-r--r-- 1 benedictjin wheel 4.4K 1 15 14:48 BenedictParser.class -rw-r--r-- 1 benedictjin wheel 3.9K 1 15 14:47 BenedictParser.java $ grun Benedict r -tree hello benedict (r hello benedict)
$ grun Benedict r -gui hello benedict ^D
在 .g4 中使用 @header{ ... }
添加
@header{ package com.yuzhouwan.antlr; }
使用 if-else
在 exit/enter()
中判别,节点与子节点之间的关系,确定是否是 operator
say : 'say' Colon Name #Colon ; `benedictListener` 将会得到一个定位粒度为 Colon 的访问节点 /** * Enter a parse tree produced by the {@code Colon} * labeled alternative in {@link benedictParser#say}. * @param ctx the parse tree */ void enterColon(benedictParser.ColonContext ctx); /** * Exit a parse tree produced by the {@code Colon} * labeled alternative in {@link benedictParser#say}. * @param ctx the parse tree */ void exitColon(benedictParser.ColonContext ctx);