3.1 语法分析的概要
解析器往往会跳过分号和括号等没有必要保存的元素,所以parser一般生成的语法树已经不再严格对应代码本身
3.2 解析器生成器
常用的解析器一般使用LR, LALR和LL文法。速度上: LL>LALR>LR,解析范围上: LL<LALR<LR。目前最主流的是LALR(yacc),本文使用LL文法(javacc)
软件名 | 能生成的语言 | 可处理的文法范围(能超前读取的token个数) |
---|---|---|
antlr | java,c,c++,go,js等 | LL(*) |
javacc | java | LL(k) |
jay | java | LALR(1) |
yacc | C | LALR(1) |
bison | C | LALR(1) |
kmyacc | C,java,js,perl | LALR(1) |
Lemon | C | LALR(1) |
Racc | Ruby | LALR(1) |
Parsec | Haskell | LL(k) |
3.3 javacc
基本使用方法javacc xxx.jj
e.g:
options{
static = false;
}
//BasicParser: ParserName
PARSER_BEGIN(BasicParser)
import java.io.*;
class BasicParser{
static public void main(String[] args){
for(String arg:args){
try{
System.out.println(arg);
System.out.println(evaluate(arg));
}
catch(ParseException ex){
ex.printStackTrace();
}
}
}
static public long evaluate(String src) throws ParseException{
Reader reader = new StringReader(src);
return new BasicParser(reader).expr();
}
}
PARSER_END(BasicParser)
SKIP: { <[" ", " ", "
", "
"]> }
TOKEN: {
<INT: (["0"-"9"])+>
}
long expr():
{
Token x,y;
}
{
LOOKAHEAD(2)
x=<INT> "+" y=<INT> <EOF>{
return Long.parseLong(x.image) + Long.parseLong(y.image);
} |
LOOKAHEAD(2)
x=<INT> "-" y=<INT> <EOF>{
return Long.parseLong(x.image) - Long.parseLong(y.image);
} |
LOOKAHEAD(2)
x=<INT> "*" y=<INT> <EOF>{
return Long.parseLong(x.image) * Long.parseLong(y.image);
} |
LOOKAHEAD(2)
x=<INT> "/" y=<INT> <EOF>{
return Long.parseLong(x.image) / Long.parseLong(y.image);
}
}
jj基本格式一般是:
//jj选项
options{
STATIC=false;
DEBUG_PARSER=true;
UNICODE_INPUT=true;
JDK_VERSION="1.5"
}
//Parser附加代码
PARSER_BEGIN(Example)
/** Simple brace matcher. */
public class Example {
/** Main entry point. */
public static void main(String args[]) throws ParseException {
Example parser = new Example(System.in);
parser.Input();
}
}
PARSER_END(Example)
//Scanner描述
SKIP: { <[" ", " ", "
", "
"]> }
//Parser描述
/** Root production. */
void Input() :
{}
{
MatchedBraces() ("
"|"
")* <EOF>
}
/** Brace matching production. */
void MatchedBraces() :
{}
{
"{" [ MatchedBraces() ] "}"
}
中文处理
必须要把Unicode_input模式设置为true