JavaCC的語法描述文件格式如下所示:
options {
JavaCC的選項
}
PARSER_BEGIN(解析器類名)
package 包名;
import 庫名;
public class 解析器類名 {
任意的Java代碼
}
PARSER_END(解析器類名)
掃描器的描述
解析器的描述
JavaCC和java一樣將解析器的內容 定義在單個類中 ,因此會在PARSER_BEGIN和PARSER_END之間描述這個類的相關內容。
下面拿一段實際代碼來做示例,並對代碼進行逐段拆分解析。
1. 示例代碼
options {
STATIC = false;
}
PARSER_BEGIN(Adder)
package com.susu.testJavaCC;
import java.io.*;
public class Adder {
public static void main(String[] args) {
for (String arg : args) {
try {
System.out.println(evaluate(arg));
// return(evaluate(arg));
} catch (ParseException ex) {
System.err.println(ex.getMessage());
}
}
}
public static long evaluate(String src) throws ParseException {
Reader reader = new StringReader(src);
return new Adder(reader).expr();
}
}
PARSER_END(Adder)
SKIP: { <[" ", "\t", "\r", "\n"]> }
TOKEN: {
<INTEGER: (["0"-"9"])+>
}
long expr():
{
Token x, y;
}
{
x=<INTEGER> "+" y=<INTEGER> <EOF>
{
return Long.parseLong(x.image) + Long.parseLong(y.image);
}
}
2. 代碼結構解析
- options塊中將STATIC選項設置為false, 將該選項設置為true的話JavaCC生成的所有成員及方法都將被定義為static,若將STATIC設置為true則所生成的解析器無法在多線程環境下使用,因此該選項總是被設置為false。(STATIC的默認值為true)
- 從PARSER_BEING(Adder)到PARSER_END(Adder)是解析器類的定義。解析器類中需要定義的成員和方法也寫在這里。為了實現即使只有Adder類也能夠運行,這里定義了main函數。
- 之后的SKIP和TOKEN部分定義了掃描器。SKIP表示要跳過空格、制表符(tab)和換行符。TOKEN表示掃描整數字符並生成token。
- long expr...開始到最后的部分定義了狹義的解析器。這部分解析token序列並執行某些操作。
3. main函數代碼解析
main函數將所有命令行參數的字符串作為計算對象的算式,依次用evaluate方法進行計算。
evaluate方法中生成了Adder類的對象實例 。並讓Adder對象來計算(解析)參數字符串src。
要運行JavaCC生成的解析器類,需要下面2個步驟:
- 生成解析器類的對象實例
- 用生成的對象調用和需要解析的語句同名的方法
第1點: JavaCC4.0和JavaCC5.0生成的解析器中默認定義有如下四種類型的構造函數。
- Parser(InputStream s):第1種的構造函數是通過傳入InputStream對象來構造解析的。這個構造函數無法設定輸入字符串的編碼,因此無法處理中文字符等。
- Parser (InputStream s, String encoding):第2種的構造函數除了InputStream對象外,還可以設置輸入字符串的編碼來生成解析器。但如果要解析中文字符串或注釋的話,就必須使用第2種/3種構造函數。
- Parser(Reader r):第3種的構造函數用於解析Reader對象所讀入的內容。
- Parser (x x x x TokenManager tm):第4種是將掃描器作為參數傳入。
解析器生成后,用這個實例調用和需要解析的語法同名的方法。這里調用Adder對象的expr方法,接回開始解析,解析正常結束后會返回語義值。