ITPub博客

首页 > 应用开发 > Java > Javacc sample

Javacc sample

原创 Java 作者:jeffersap 时间:2007-08-28 17:21:26 0 删除 编辑

[@more@]为了让词法分析做得更简单,我们通常都不会在文法分析的时候,使用“(”,“)”等字符号串来表示终结符号,而需要转而使用LPAREN, RPAREN这样的整型符号来表示。


PARSER_BEGIN(Grammar)
public class Grammar implements NodeType {
public ParseTreeNode GetParseTree(InputStream in) throws ParseException
{
Grammar parser =new Grammar(in);
return parser。Expression();
}
}
PARSER_END(Grammar)
SKIP :
{
" " | " " | " " | " "
}
TOKEN :
{
< ID: ["a"-"z","A"-"Z","_"> ( ["a"-"z","A"-"Z","_","0"-"9"> )* >
| < NUM: ( ["0"-"9"> )+ >
| < PLUS: "+" >
| < MINUS: "-" >
| < TIMERS: "*" >
| < OVER: "/" >
| < LPAREN: "(" >
| < RPAREN: ")" >
}

ParseTreeNode Expression() :
{
ParseTreeNode ParseTree = null;
ParseTreeNode node;
}
{
( node=Simple_Expression()
{
if(ParseTree == null)
ParseTree =node;
else
{
ParseTreeNode t;
t= ParseTree;
while(t.next != null)
t=t.next;
t.next = node;
}
}
)*
{ return ParseTree; }

}
ParseTreeNode Simple_Expression() :
{
ParseTreeNode node;
ParseTreeNode t;
int op;
}
{
node=Term(){}
(
op=addop() t=Term()
{
ParseTreeNode newNode = new ParseTreeNode();
newNode.nodetype = op;
newNode.child[0] = node;
newNode.child[1] = t;
switch(op)
{
case PlusOP:
newNode.name = "Operator: +";
break;
case MinusOP:
newNode.name = "Operator: -";
break;
}
node = newNode;
}
)*
{ return node; }
}
int addop() : {}
{
{ return PlusOP; }
| { return MinusOP; }
}
ParseTreeNode Term() :
{
ParseTreeNode node;
ParseTreeNode t;
int op;
}
{
node=Factor(){}
(
op=mulop() t=Factor()
{
ParseTreeNode newNode = new ParseTreeNode();
newNode.nodetype = op;
newNode.child[0] = node;
newNode.child[1] = t;
switch(op)
{
case TimersOP:
newNode.name = "Operator: *";
break;
case OverOP:
newNode.name = "Operator: /";
break;
}
node = newNode;
}
)*
{
return node;
}
}
int mulop() :{}
{
{ return TimersOP; }
| { return OverOP; }
}
ParseTreeNode Factor() :
{
ParseTreeNode node;
Token t;
}
{
t=
{
node=new ParseTreeNode();
node.nodetype= IDstmt;
node.name = t.image;
return node;
}
|
t=
{
node=new ParseTreeNode();
node.nodetype= NUMstmt;
node.name = t.image;
node.value= Integer.parseInt(t.image);
return node;
}
|
node=Simple_Expression()
{
return node;
}
}

其中SKIP中的定义就是在进行词法分析的同时,忽略掉的记号。TOKEN中的,就是需要在做词法分析的时候,识别的词法记号。当然,这一切都是以正则表达式来表示的。
这个例子就有多个非终结符号,可以看出,我们需要为每个非终结符号写出一个过程。不同的非终结符号的识别过程中可以互相调用。

以Simple_Expression()过程为例,它的产生式是Expression -> Term { addop Term },而在javacc的输入文件格式是,它的识别是这样写的node=Term(){} ( op=addop() t=Term(){ … })* 前面说过,这里的”*”符号和正则表达式是一样的,就是0次到无限次的重复。那么Simple_Expression等于文法Term Addop Term Addop Term Addop Term … 而Addop也就相当于PLUS和MINUS两个运算符号。这里我们在写Expression的文法的时候,同时还使用了赋值表达式,因为这个和Yacc 不同的时候,Javacc把文法识别完全地做到了函数过程中,那么如果我们要识别Simple_Expression的文法,就相当于按顺序识别Term 和Addop两个文法,而识别那个文法,就相当于调用那两个非终结符的识别函数。正是这一点,我觉得Javacc的文法识别处理上就很接近程序的操作过 程,我们不需要像YACC那样使用严格的文法表示格式,复杂的系统参数了。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10230672/viewspace-966506/,如需转载,请注明出处,否则将追究法律责任。

上一篇: Javacc的例子
下一篇: 定价与条件
请登录后发表评论 登录
全部评论
  • 博文量
    224
  • 访问量
    157161