私は、単純な式と条件付きステートメントを使用して単純なスクリプト言語を定義する javacc 文法を持っています。
void Statement() : {}
{
Assignment()
|
IfStatement()
}
void Assignment() : {}
{
RealIdentifier() "=" SimpleExpression()
|
StringIdentifier() "=" StringExpression()
}
void IfStatement() : {}
{
"IF" Expression() "THEN" Block()
(
"ENDIF;"
|
"ELSE" Block() "ENDIF;"
)
}
void Expression() #void : {}
{
SimpleExpression()
(
"<" SimpleExpression() #LTNode(2)
|
">" SimpleExpression() #GTNode(2)
|
"<=" SimpleExpression() #LENode(2)
|
">=" SimpleExpression() #GENode(2)
|
"==" SimpleExpression() #EQNode(2)
|
"!=" SimpleExpression() #NENode(2)
)*
}
void SimpleExpression() #void : {}
{
Term()
(
"+" Term() #AddNode(2)
|
"-" Term() #SubsNode(2)
|
"|" Term() #OrNode(2)
)*
}
void Term() #void : {}
{
Factor()
(
"*" Factor() #MultNode(2)
|
"/" Factor() #DivNode(2)
|
"&" Factor() #AndNode(2)
)*
}
void Factor() #void : {}
{
Real()
|
RealIdentifier()
|
Function()
|
"(" Expression() ")"
|
"!" Factor() #NotNode(1)
|
StringExpression()
}
void Function() :
{
Token t;
int args = 0;
}
{
t = <FUNCTION> { jjtThis.setID(t.image, legacyCharset); } "(" args = ArgumentList() ")"
{ jjtThis.setArgs(args); }
}
int ArgumentList() #void :
{
int args = 0;
}
{
Expression() {args++;} ( "," Expression() {args++;} )*
{ return args; }
}
void StringIdentifier() :
{
Token t;
}
{
t = <STRING_IDENTIFIER>
{
System.out.println("kind="+t.kind+" image="+t.image);
}
}
void RealIdentifier() :
{
Token t;
}
{
t = <REAL_IDENTIFIER>
{
System.out.println("kind="+t.kind+" image="+t.image);
}
}
最初の明らかな問題は、Expression の定義方法にあり、IfStatement の定義に使用されるため、簡単に次のような結果になる可能性があります。 If (variable1 < variable2 >= variable3 )
次のように、条件式のロジックを一般的な式のロジックから分離することで、それを修正しようとしています。
void IfStatement() : {}
{
"IF" ConditionalExpression() "THEN" Block()
(
"ENDIF;"
|
"ELSE" Block() "ENDIF;"
)
}
void ConditionalExpression() #void : {}
{
SimpleExpression()
(
"<" #LTNode(2)
|
">" #GTNode(2)
|
"<=" #LENode(2)
|
">=" #GENode(2)
|
"==" #EQNode(2)
|
"!=" #NENode(2)
)SimpleExpression()
}
void Expression() #void : {}
( SimpleExpression() )*
}
生成された jj ファイルをコンパイルすると、次の警告が表示されました: 警告: 210 行目、3 列目の (...)* 構造の選択競合。 " ネストされた展開には 2 以上の先読みを使用することを検討してください。
エラー行番号は、生成された jj ファイル内の行の番号です。解析されているものが ConditionalExpression であるか Expression であるかを判断できないため、SimpleExpression に遭遇したときに競合が発生すると想定しました。
void Expression() #void : {}
{
( LOOKAHEAD(2) SimpleExpression() )*
}
その後
void ConditionalExpression() #void : {}
{
( LOOKAHEAD(2)
SimpleExpression()
(
しかし、それは消えませんでした。選択の競合があると言っているjjファイルの行は
void Statement() : {/*@bgen(jjtree) Statement */
ASTStatement jjtn000 = new ASTStatement(JJTSTATEMENT);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
/*@egen*/} // <-------------------------------------- line 210
{/*@bgen(jjtree) Statement */
try {
/*@egen*/
Assignment()
|
もう 1 つの問題は、演算子の優先順位が何らかの形で台無しになっていることです。 IF ( "a" == "a" | "c"=="c" ) のようなものは | 2 番目のオペランドとして "c" を使用する 2 番目の == 演算子の前に解釈され、それが ClassCastException を与えるため、これを修正するには文法全体を書き直す必要があると結論付けたので、複合の単一の条件の周りに括弧を強制することを考えましたこのような条件文 if ( ("a" == "a") | ( "c" == "c" ) ) 方法がわかりません。