2

私は、単純な式と条件付きステートメントを使用して単純なスクリプト言語を定義する 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" ) ) 方法がわかりません。

4

2 に答える 2

2

kleen-star の代わりに を*使用?して、関係式の右辺 (演算子を含む) をオプションにして、1 つSimpleExpression()でも一致するようにします。

void Expression() #void : {}
{
  SimpleExpression()
  ( "<"  SimpleExpression() #LTNode(2)
  | ">"  SimpleExpression() #GTNode(2)
  | "<=" SimpleExpression() #LENode(2)
  | ">=" SimpleExpression() #GENode(2)
  | "==" SimpleExpression() #EQNode(2) 
  | "!=" SimpleExpression() #NENode(2)
  )?
}

これにより競合が発生することはありません。

于 2012-12-20T11:38:06.590 に答える
0

2番目の問題について

もう1つの問題は、演算子の優先順位がどういうわけか台無しになっていることです.IF( "a" == "a" | "c"=="c")のようなものは|になります 2 番目のオペランドとして "c" を使用して 2 番目の == 演算子の前に解釈され、ClassCastException が発生した場合、

演算子に関連する文法規則を投稿していないため、|診断が困難です。あなたが提案するソリューションは必須ではありません。

言語設計に関するコメントが気にならないことを願っています: 文法を使用して型の正確性を強制しようとすることは、通常、適切な選択ではありません。

于 2013-01-28T18:23:53.360 に答える