上一節(jié),我們通過Antlr快速的落地實(shí)現(xiàn)了Token的解析,這一節(jié)我們還是基于Antlr來實(shí)現(xiàn)語法的解析。
語法分析相對來講就復(fù)雜多了,我們需要對Token進(jìn)行推導(dǎo)與組合,生成我們想要表達(dá)的式子。
我們先來看一個(gè)簡單的例子:
a + b * c
這個(gè)看上去很簡單的表達(dá)式,我們最終想要得到的結(jié)果是b * c 再與 a相加,而不是a + b再乘以 c。
這里就涉及到一個(gè)優(yōu)先級的問題,Antlr支持通過右邊產(chǎn)生式的順序來定義優(yōu)先級。
語法規(guī)則是由上下文無關(guān)文法表示的,而上下文無關(guān)文法是由一組替換規(guī)則(又叫產(chǎn)生式)組成的,比如算術(shù)表達(dá)式的文法規(guī)則可以表達(dá)成下面這種形式:
add -> mul | add + mul
mul -> pri | mul * pri
pri -> Id | Num | Operator
pri表示基礎(chǔ)表達(dá)式,他可以推導(dǎo)成Id(標(biāo)識符),Num(數(shù)字), Operator(操作符)
mul表示可以推導(dǎo)成一個(gè)基礎(chǔ)表達(dá)式或者是mul乘以pri
add表示可以推導(dǎo)成一個(gè)mul或者add 加上 mul
按這個(gè)規(guī)則我們來推導(dǎo)一下a + b * c.
優(yōu)先級高的后推導(dǎo),優(yōu)先級低的先推薦。
嘗試將這個(gè)式子推薦成add,發(fā)現(xiàn)剛好符合要求add+mul
add+mul 推導(dǎo)成mul+mul
再推導(dǎo)成pri+mul
再推導(dǎo)成pri+mul*pri
再推導(dǎo)成pri+pri*pri
最后推導(dǎo)成pri+pri*pri
以上的推導(dǎo)是建立在你有一定的編譯器前端認(rèn)識的基礎(chǔ)之上,在這之前你需要知道推導(dǎo)的左遞歸與結(jié)合性的問題。
Antlr已經(jīng)幫我們處理好了左遞歸,我們可以放心的按左遞歸的規(guī)則來書寫。
至于結(jié)合性的問題,正如我上面提到的,a + b * c 不能推導(dǎo)成a + b 再乘以c,我們可能通過Antlr規(guī)則產(chǎn)生式的順序來確保結(jié)合性的正確。
上面說了很多都比較空洞, 接下來我們通過Antlr來實(shí)現(xiàn)我們的語法分析
grammar FlexDSLScript;
import FlexDSLLexer;
/// 表達(dá)式,按右邊產(chǎn)生式的順序來依次優(yōu)先推導(dǎo)
expression:
primary
| dot = '.' expression
| expression dot = '.' expression
| '(' expression ')'
| FOR Id IN Id
| expression postfix = ('++' | '--')
| prefix = ('++' | '--') expression
| expression bop = ('*' | '/' | '%') expression
| expression bop = ('+' | '-') expression
| expression bop = ('<' | '<=' | '>' | '>=') expression
| expression bop = ('==' | '!=') expression
| expression bop = ('&&' | '||') expression
| expression bop = '?' expression bop = ':' expression;
primary:
Id
| StringLiteral
| IntLiteral
| DoubleLiteral
| TF = (True | False);
首先我們需要導(dǎo)入語法分析規(guī)則
我們定義了最基礎(chǔ)的表達(dá)未
primary, 他可以推導(dǎo)出Id(標(biāo)簽符: 變量名稱),
StringLiteral(字符串字面量),
IntLiteral(整形字面量),
DoubleLiteral(浮點(diǎn)書字面量),
TF(true|false)
expression 通過順序定義了推導(dǎo)邏輯,優(yōu)先級高的寫在前面,優(yōu)先級低的寫后面 寫好規(guī)則文件之后我們來編譯一下
antlr4 FlexDSLScript.g4
javac *.java
編譯完成后運(yùn)行
grun FlexDSLScript expression -gui
在終端里輸入這個(gè)表達(dá)式,然后按Alt+D(mac), Windows應(yīng)該是Control+D,輸入一下結(jié)束符,
接下來java彈出一個(gè)對話框,直觀的展示了解析后的AST
通過遍歷這個(gè)AST我們就可以得到這個(gè)表達(dá)式最后的結(jié)果了。
下一節(jié)我們來實(shí)現(xiàn)語義分析,也就是對AST的遍歷求運(yùn)算。
-
語法
+關(guān)注
關(guān)注
0文章
44瀏覽量
10165 -
ANTLR
+關(guān)注
關(guān)注
0文章
3瀏覽量
5834
發(fā)布評論請先 登錄

關(guān)于antlr詞法分析器的使用
Linux內(nèi)核中GNU C擴(kuò)展的一些常用C語言語法分析
一個(gè)高效的語法分析器生成工具
YACC在ATLAS語言語法分析中的沖突消解研究
編譯原理實(shí)踐環(huán)節(jié)模擬試題
借助Lex和Yacc進(jìn)行詞法語法分析
基于ANTLR的試卷識別和導(dǎo)入系統(tǒng)

Java程序的工作原理是怎樣的
開源L2C編譯器前端語法分析器及驗(yàn)證過程
自頂向下的語法分析器—采用遞歸下降方法

評論