基於JavaCC的語法描述
使用JavaCC從token序列中識別出"語句" “表達式” “函數調用” 等語法單位的方法。
只要爲JavaCC描述“語句” “表達式” “函數調用” 這樣的語法單位各自是由怎樣的token序列構成的,就能夠對該語法進行分析(parse)。
例如:最簡單的賦值表達式可以描述爲“符號” “ “=” ” ”表達式“ 的排列。 換言之, 如果存在”符號“ ” ”=“ “ ”表達式“ 這樣的排列 那就是賦值表達式。這個規則在JavaCC中表示成下面這樣:
assign():
{}
{
<IDENTIFIER> "=" expr()
}
assign()對應賦值表達式,<IDENTIFIER>對應token標示符,"="對應"="token。
像<IDENTIFIER>這樣已經在掃描器中定義的token,在描述解析器時可以直接使用。其他的如"="這樣的固定字符串也因爲可以表示token,所以也能在規則中使用。 另外,表達式expr()自身也是多個token構成的,這樣的情況下需要進一步對expr()的規則進行描述,以下是僞描述:
expr():
{}
{
expr() "+" expr()
或expr() "-" expr()
或expr() "*" expr()
..
.
}
終端符與非終端符
JavaCC中將"語句" "函數調用" "表達式" 等非token的語法單位稱爲非終端符,並將非終端符像java的函數調用一樣在後面加上括號寫成stmt()或expr()。
終端符可以歸納爲token。使用在掃描器中定義的名稱,可以寫成<INDENTIFIER>或<LONG>。並且JavaCC中除了掃描器中定義的token以外, "="、"+"、"==" 這樣的字符串字面量也可以作爲終端符來使用
種類 | 含義 | 例 |
---|---|---|
終端符 | token | <IDENTIFIER>、<LONG>、"="、"==" |
非終端符 | 由終端符排列組成的語法單位 | stmt()、expr()、assign() |
在畫語法時,終端符位於樹的枝幹的末端(終端),非終端符由於是由其他符號的列組成的,所以位於分叉處。
JavaCC的EBNF表示法
JavaCC使用EBNF(Extended Backus-Naur-Form)的表示法來描述語法規則。下表中羅列了JavaCC的解析器生成所使用的EBNF表示法。
種類 | 例子 |
---|---|
終端符 | <IDENTIFIER>或"," |
非終端符 | name() |
連接 | <UNISGNED><LONG> |
重複0次或多次 | (","expr())* |
重複1次或多次 | (stmt())+ |
選擇 | <CHAR>丨<SHORT>丨<INT>丨<LONG> |
可以省略 | [<ELSE>stmt()] |
1. 連接
連接是指特定符號相連續的模式。例如C語言continue語句是保留字continue和分號的排列。JavaCC中將該規則寫成如下形式:
<CONTINUE> ";"
<CONTINUE>是表示保留字continue的終端符,“:”是表示字符自身的終端符。
2. 重複0次或多次
下面的寫法表示0個或多個語句排列:
(stmt())*
下面的例子,函數的參數是由逗號分隔的表達式排列組成的,即expr之後排列着0個或多個逗號和expr的組合:
expr() ("," expt())*
3. 重複1次或多次
(stmt())+
上面的代碼描述了非終端符stmt()重複1次或多次。
4. 選擇
選擇即爲從多個選項中選擇1個的規則。例如cflat的類型由void、char、unsigned、char等:
<VOID> | <CHAR> | <UNSIGNED> | <CHAR> | ...
5. 可以省略
定義變量時可以設置初始值也可以不設置,這種在JavaCC中可以寫成:
storage() typeref() name() ["=" expr()] ";"