首页 > 开发 > Java > 正文

javaCC学习笔记

2024-07-13 09:54:52
字体:
来源:转载
供稿:网友

javacc的功能和yacc相似,主要根据bnf范式生成解析程序,不过javacc是集合了词法分析和语法分析生成java解析代码,主页为:https://javacc.dev.java.net/

javacc有三个工具

javacc 用来处理语法文件(jj)生成解析代码;

jjtree 用来处理jjt文件,生成树节点代码和jj文件,然后再通过javacc生成解析代码;

jjdoc 根据jj文件生成bnf范式文档(html)

javacc使用的各种语言的grammar 文件这里有很多http://www.cobase.cs.ucla.edu/pub/javacc/ ,例如html,xml,python,vb…..,很多足够用了,呵呵。



javacc 的使用

javacc生成的文件中,最主要的是《grammar》.java这个就是解析器的主程序了了,《grammar》名由jj中定义。



现在根据例子说明jj文件的定义:

bnf范式为:

expression
::=
( ( <newline> )* simple_expression <newline> )* <eof>

simple_expression
::=
term ( addop term )*

addop
::=
<plus>


|
<minus>

term
::=
factor ( mulop factor )*

mulop
::=
<timers>


|
<over>

factor
::=
<id>


|
<num>


|
<minus>


|
<plus>


|
<lparen> simple_expression <rparen>




/*这是一个整数的四则运算的例子*/

/* 运行 javacc grammar.jj

javac *.java

java grammar

>>> 1+1*(1+1)

3

>>>^z

*/



parser_begin(grammar) /*解析代码的入口*/



public class grammar {



public static final int plusop=1;

public static final int minusop=2;

public static final int timersop=3;

public static final int overop=4;





public static void main(string args[]) throws parseexception {

grammar parser = new grammar(system.in);



parser.expression();

}

}



parser_end(grammar)



skip : /* 不处理的字符*/

{

" " | "/t"

}



token : /*生成token的字符定义*/

{



< id: ["a"-"z","a"-"z","_"] ( ["a"-"z","a"-"z","_","0"-"9"] )* >



| < num: ( ["0"-"9"] )+ >



| < plus: "+" >



| < minus: "-" >



| < timers: "*" >



| < over: "/" >



| < lparen: "(" >



| < rparen: ")" >

| <newline: ("/r/n"|"/n"|"/r")>

}







void expression() :

/*完成 expression ::=( ( <newline> )* simple_expression <newline> )* <eof> 的配陪*/

{



int value=0; /* 这个{}中是expression()的定义的局部变量*/



}



{



{

system.out.print(">>>");

}

( (<newline> /* 首先匹配newline 这个taken,完成后转到下一个解析*/

{

system.out.print(">>>"); /*在<newline>下的{}中为如果匹配到<newline>执行的java代码。*/

}

)* value= simple_expression() <newline> /*在换行之前simple_expression()解析表达式 ,输入换行后,一个预算解析完成*/



{system.out.println(value);

system.out.print(">>>");/*在<newline>下的{}中为完成表达式解析,匹配到<newline>执行的java代码。*/



}

)*

<eof> /*系统定义的taken,输入结束符*/

}



int simple_expression() :

/*完成simple_expression ::=bnf term ( addop term )*配陪 */

{

/* 这个{}中是simple_expression()的定义的局部变量*/



int value;



int tvalue;



int op;



}



{



value= term (){} /*配陪term 相*/



(



op=addop() tvalue=term()



{

switch(op)

{

case plusop:

value=value+tvalue;

break;

case minusop:

value=value - tvalue;

break;

}

}

)* /*匹配 ( addop term )* */

{ return value; }

}



int addop() : {}

{

<plus> { return plusop; }

| <minus> { return minusop; }

}



int term() :

{

int value;

int tvalue;

int op;

}

{

value=factor(){}

(

op=mulop() tvalue=factor()

{

switch(op)

{

case timersop:

value=value * tvalue;

break;

case overop:

value=value / tvalue;

break;

}

}



)*

{

return value;

}

}

int mulop() :{}

{

<timers> { return timersop; }

| <over> { return overop; }

}



int factor() :

{

int value;

token t;

}

{

t=<id> /*获得<id>的解析的值*/

{

value=100;

return value;



}

|

t=<num>

{

value= (integer.valueof(t.image)).intvalue();

return value;

}

|

t=<minus>

{

value=0-factor();

return value;

}

|

t=<plus>

{



value=factor();

return value;

}

|



<lparen> value=simple_expression() <rparen>

{

return value;

}

}



根据例子: 基本上是一个taken下跟一个{}用于处理当前tabkn的java代码





jjtree的使用:



jjtree的使用,需要根据实际情况写自己的node类,但是都必须实现node.java接口,jjtree提供一个simplenode.java的简单实现,也可以继承它,或者重写这个类。



给出一个javacc自己带例子,也是四则运算:

语法定义:

start
::=
expression ";"

expression
::=
additiveexpression

additiveexpression
::=
( multiplicativeexpression ( ( "+" | "-" ) multiplicativeexpression )* )

multiplicativeexpression
::=
( unaryexpression ( ( "*" | "/" | "%" ) unaryexpression )* )

unaryexpression
::=
"(" expression ")"


|
identifier


|
integer

identifier
::=
<identifier>

integer
::=
<integer_literal>






options {

multi=true;

visitor=true; /*实现匹配的visitor模式代码*/

node_default_void=true; /* 解析函数默认不生成node类*/

}

/*jtt 默认的生成node类名,都带ast前缀加上当前解析的语意的名称*/



parser_begin(eg4)



class eg4 {

public static void main(string args[]) {

system.out.println("reading from standard input...");

eg4 t = new eg4(system.in);

try {

aststart n = t.start();

eg4visitor v = new eg4dumpvisitor();

n.jjtaccept(v, null);

system.out.println("thank you.");

} catch (exception e) {

system.out.println("oops.");

system.out.println(e.getmessage());

e.printstacktrace();

}

}

}



parser_end(eg4)

skip :

{

" "

| "/t"

| "/n"

| "/r"

| <"//" (~["/n","/r"])* ("/n"|"/r"|"/r/n")>

| <"/*" (~["*"])* "*" (~["/"] (~["*"])* "*")* "/">

}



token : /* literals */

{

< integer_literal:

<decimal_literal> (["l","l"])?

| <hex_literal> (["l","l"])?

| <octal_literal> (["l","l"])?

>

|

< #decimal_literal: ["1"-"9"] (["0"-"9"])* >

|

< #hex_literal: "0" ["x","x"] (["0"-"9","a"-"f","a"-"f"])+ >

|

< #octal_literal: "0" (["0"-"7"])* >

}



token : /* identifiers */

{

< identifier: <letter> (<letter>|<digit>)* >

|

< #letter: ["_","a"-"z","a"-"z"] >

|

< #digit: ["0"-"9"] >

}



aststart start() #start : {} /* #start生成定义的节点类,名称为 前缀 + start.java*/

{

expression() ";"

{ return jjtthis; }

}





void expression() : {}

{

additiveexpression()

}



void additiveexpression() : {}

{

(

multiplicativeexpression() ( ( "+" | "-" ) multiplicativeexpression() )*

) #add(>1) /* add # 当满足条件(>1),add生成定义的节点类,名称为 前缀 + add.java*/

}



void multiplicativeexpression() : {}

{

(

unaryexpression() ( ( "*" | "/" | "%" ) unaryexpression() )*

) #mult(>1) /* # mult 当满足条件(>1),mult生成定义的节点类,名称为 前缀 + mult.java*/



}



void unaryexpression() : {}

{

"(" expression() ")" | identifier() | integer()

}



void identifier() #myotherid : /* # myotherid生成定义的节点类,名称为 前缀 + myotherid.java*/

{

token t;

}

{

t=<identifier>

{

jjtthis.setname(t.image);

}

}



void integer() #integer : {} /* # integer生成定义的节点类,名称为 前缀 + integer.java*/



{

<integer_literal>

}





jjdoc的使用很简单 。





如果需要生成其它语言的(例如c#)解析器,除了处理c的yacc和lex外,antlr(http://www.antlr.org/)也是一个不错的选择。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表