今天接触到了javacc!
1,官方网站https://javacc.dev.java.net/
2,使用javacc处理格式化文本
什么是javacc,他该怎么用麻烦您请教一下google吧,有详细解答。
接着解释什么是终结符。终结符就是一个正则表达式,他是一个什么样的形式差不多已经确定了。比如我要定义一个冒号,就可以这么写< COLON : “:”>, 要是定义一个整数我可以这么写 < INTEGER: ([”0″-”9″])+>, []表示这里面的东西任选一个,”0″-”9″是一个缩写,你也可以写成类似[”0″|”1″|”2″|”3″] 为了用那个加号,要先用括号扩起来,后面那个加号表示方括号里面内容可以出现一次或者多次比如0,02,3482什么的都可以了。
接着讲非终结符 把终结符串串就成了非终结符。玩把深沉,给个递归的定义:非终结符=终结符+非终结符 ,当然写成非终结符=非终结符+终结符。不过这两种不是完全等价的,有兴趣的可以参考龙书。
干说说不清,举个例子。假设我现在有这么一个存储电话号码的文本文件。
tom:home 12345
office 23456
peter: office 34567
alice:home 45678
语法很简单了,两个关键字,分别是home和office表示家里或者办公室电话,要是没有就可以不写,姓名和电话条目后面用分号格开。
首先我们把这整个文件看成是一个大的非终结符,就叫他parser吧。我们看下parse的推导过程:(约定小写的是非终结符,大写的是终结符)
parser--> (people_item)* //这里用*表示可以出现一次或者多次,因为文件可以空的啊
people_item --> STRING COLON (number_item)*
number_item–> OFFICE INTEGER
|HOME_INTEGER
以上就解析例子文本的文法推导过程,推导说白了就是把一个巨复杂的非终结符演算成全是终结符,而且没有歧义
对照着以上的推导过程我们给出javacc看的懂的jj文件,说明都放到注释里了
options
{
DEBUG_PARSER=true; //加上这个系统参数是为了可以显示文法推导的过程
}
PARSER_BEGIN(TelParser) //TelParser就是你最想要得那个东西,你也可以叫其他名字
public class TelParser //这块和写普通的java类比较像,不过javacc会自动加进来一些方法用来解析非终结符
{
public static void main(String args[])
{
TelParser parser;
if (args.length == 1)
{
System.out.println(”Reading from file ” + args[0] + ” . . .”);
try
{
parser = new TelParser(new java.io.FileInputStream(args[0]));
//下面这句就是文法分析的入口啊,表示整个文件的非终结符
//parser()是半自动生成的,以为后文你对他进行了说明
parser.parser();
System.out.println(”ok”);
}catch (Exception e)
{
e.printStackTrace();
return;
}
}
}
}
PARSER_END(TelParser)
//要忽略的东西都放到SKIP里来
/* WHITE SPACE */
SKIP :
{
” ”
| “/t”
| “/n”
| “/r”
| “/f”
| “/r/n”
}
//TOKEN是定义终结符的,不多说了,看看就懂了把
/* SEPARATORS */
TOKEN :
{
< COLON : “:”>
| < EQU: “=” >
| < LBRACE: “{” >
| < RBRACE: “}” >
| < SEMICOLON: “;” >
| < COMMA: “,” >
}
/* RESERVED WORDS*/
TOKEN :
{
<HOME : “home”>
|<OFFICE : “office”>
}
/*LITERALS*/
TOKEN :
{
< INTEGER: ([”0″-”9″])+>
| < STRING : ([”A”-”Z”, “a”-”z”, “0″-”9″])+ >
}
//入口非终结符
void parser()://冒号不要丢啊
{
//语法分析阶段可以放一些变量申明
}
{
(peopleItem())* //看推导开始了
}
void peopleItem():
{
}
{
<STRING><COLON>(numberItem())*
}
void numberItem():
{
}
{
[<OFFICE>|<HOME>] <INTEGER>
}
以上就是文法分析的过程
但是也许你会问,按照上面的文法,我给一个人写两遍office电话也是合法的。是的,是有这个问题。这个问题需要在语法分析阶段解决了。下回再说