15

私には、JavaCCを使用して、講師から提供された言語のセマンティック分析を使用したトップダウンパーサーを作成する割り当てがあります。制作ルールを書き留めてあり、エラーはありません。私は自分のコードにJJTreeを使用する方法に完全に固執しており、チュートリアルのためにインターネットを精査する時間はどこにもありません。コードにJJTreeを実装する方法を説明するために誰かが時間を割くことができるだろうかと思っていますか?または、どこかに隠されたステップバイステップのチュートリアルがある場合、それは大きな助けになります!

役立つ場合に備えて、私の制作ルールをいくつか紹介します。前もって感謝します!

void program() : {}
{
  (decl())* (function())* main_prog()
}

void decl() #void : {}
{
  (
    var_decl() | const_decl()
   )
}

void var_decl() #void : {}
{
  <VAR> ident_list() <COLON> type()
 (<COMMA> ident_list() <COLON> type())* <SEMIC>
}

void const_decl()  #void : {}
{
  <CONSTANT> identifier() <COLON> type() <EQUAL> expression()
 ( <COMMA> identifier() <COLON> type() <EQUAL > expression())* <SEMIC>
} 

void function() #void : {}
{
  type() identifier() <LBR> param_list() <RBR>
  <CBL>
  (decl())*
  (statement() <SEMIC> )*
  returnRule() (expression() | {} )<SEMIC>
  <CBR>
}
4

2 に答える 2

54

jjJavaCCを使用してASTを作成することは、(ファイルで定義された)「通常の」パーサーを作成することによく似ています。すでに実用的な文法がある場合は、(比較的)簡単です:)

ASTを作成するために必要な手順は次のとおりです。

  1. jj文法ファイルの名前を次のように変更しますjjt
  2. ルートラベル飾ります(斜体の単語は私自身の用語です...)
  3. 文法を呼び出すjjtreeと、ファイルが生成されますjjtjj
  4. javacc生成されたjj文法を呼び出す
  5. java生成されたソースファイルをコンパイルします
  6. 試して

javacc.jarMacOSまたは*nixを使用していて、ファイルが文法ファイルと同じディレクトリにありjavajavacシステムのPATHにあると仮定して、簡単なステップバイステップのチュートリアルを次に示します。

1

jj文法ファイルが呼び出されたと仮定してTestParser.jj、名前を変更します。

mv TestParser.jj TestParser.jjt

2

ここで注意が必要なのは、適切なAST構造が作成されるように文法を装飾することです。AST(またはノード、またはプロダクションルール(すべて同じ))の後に(およびその前に)識別子を追加して、ASTを装飾します。元の質問では、さまざまなプロダクションに多くのことがあります。つまり、さまざまなプロダクションルールに対して同じタイプのASTを作成しているということです。これはあなたが望むものではありません。#:#void

プロダクションを装飾しない場合は、プロダクションの名前がノードのタイプとして使用されます(したがって、削除できます#void)。

void decl() :
{}
{
     var_decl()
  |  const_decl()
}

var_decl()これで、ルールは、ルールまたは返されたASTを単純に返しますconst_decl()

var_declここで、(簡略化された)ルールを見てみましょう。

void var_decl() #VAR :
{}
{
  <VAR> id() <COL> id() <EQ> expr() <SCOL>
}

void id() #ID :
{}
{
  <ID>
}

void expr() #EXPR :
{}
{
  <ID>
}

タイプで飾りました#VAR。これは、このルールが次のツリー構造を返すことを意味します。

    VAR 
   / | \
  /  |  \
ID  ID  EXPR

ご覧のとおり、端末はASTから破棄されます。これは、idandexprルールが<ID>端末が一致したテキストを失うことも意味します。もちろん、これはあなたが望むものではありません。ターミナルの内部テキストを一致させておく必要があるルールの場合.value、ツリーのを.image一致したターミナルのに明示的に設定する必要があります。

void id() #ID :
{Token t;}
{
  t=<ID> {jjtThis.value = t.image;}
}

void expr() #EXPR :
{Token t;}
{
  t=<ID> {jjtThis.value = t.image;}
}

入力"var x : int = i;"を次のようにします。

       VAR 
        |
    .---+------.
   /    |       \
  /     |        \
ID["x"] ID["int"] EXPR["i"]

これは、ASTの適切な構造を作成する方法です。以下は、mainすべてをテストするための小さな方法を含む、独自の文法の非常に単純なバージョンである小さな文法を示しています。

// TestParser.jjt
PARSER_BEGIN(TestParser)

public class TestParser {
  public static void main(String[] args) throws ParseException {
    TestParser parser = new TestParser(new java.io.StringReader(args[0]));
    SimpleNode root = parser.program();
    root.dump("");
  }
}

PARSER_END(TestParser)

TOKEN :
{
   < OPAR  : "(" > 
 | < CPAR  : ")" >
 | < OBR   : "{" >
 | < CBR   : "}" >
 | < COL   : ":" >
 | < SCOL  : ";" >
 | < COMMA : "," >
 | < VAR   : "var" >
 | < EQ    : "=" > 
 | < CONST : "const" >
 | < ID    : ("_" | <LETTER>) ("_" | <ALPHANUM>)* >
}

TOKEN :
{
   < #DIGIT    : ["0"-"9"] >
 | < #LETTER   : ["a"-"z","A"-"Z"] >
 | < #ALPHANUM : <LETTER> | <DIGIT> >
}

SKIP : { " " | "\t" | "\r" | "\n" }

SimpleNode program() #PROGRAM :
{}
{
  (decl())* (function())* <EOF> {return jjtThis;}
}

void decl() :
{}
{
     var_decl()
  |  const_decl()
}

void var_decl() #VAR :
{}
{
  <VAR> id() <COL> id() <EQ> expr() <SCOL>
}

void const_decl() #CONST :
{}
{
  <CONST> id() <COL> id() <EQ> expr() <SCOL>
}


void function() #FUNCTION :
{}
{
  type() id() <OPAR> params() <CPAR> <OBR> /* ... */ <CBR>
}

void type() #TYPE :
{Token t;}
{
  t=<ID> {jjtThis.value = t.image;}
}

void id() #ID :
{Token t;}
{
  t=<ID> {jjtThis.value = t.image;}
}

void params() #PARAMS :
{}
{
  (param() (<COMMA> param())*)?
}

void param() #PARAM :
{Token t;}
{
  t=<ID> {jjtThis.value = t.image;}
}

void expr() #EXPR :
{Token t;}
{
  t=<ID> {jjtThis.value = t.image;}
}

3

jjtreeクラス(に含まれてjavacc.jarいる)にファイルを作成させjjます。

java -cp javacc.jar jjtree TestParser.jjt

4

前の手順でファイルが作成されましたTestParser.jj(すべて問題がなかった場合)。それを処理させてくださいjavacc(に存在しjavacc.jarます):

java -cp javacc.jar javacc TestParser.jj

5

すべてのソースファイルをコンパイルするには、次の手順を実行します。

javac -cp .:javacc.jar *.java

(Windowsでは、次のようにしますjavac -cp .;javacc.jar *.java:)

6

真実の瞬間が到来しました。すべてが実際に機能するかどうかを見てみましょう。パーサーに入力を処理させるには:

var n : int = I; 

const x : bool = B; 

double f(a,b,c) 
{ 
}

以下を実行します。

java -cp . TestParser "var n : int = I; const x : bool = B; double f(a,b,c) { }"

コンソールに次のように印刷されているはずです。

プログラム
 decl
  VAR
   ID
   ID
   EXPR
 decl
  CONST
   ID
   ID
   EXPR
 働き
  タイプ
  ID
  パラメータ
   パラム
   パラム
   パラム

'が一致したテキストは表示されないことに注意してください。ただし、ID私を信じてください。それらはそこにあります。メソッドdump()は単にそれを表示しません。

HTH

編集

式を含む実用的な文法については、私の次の式エバリュエーターを見ることができます:https ://github.com/bkiers/Curta (文法はにありsrc/grammarます)。バイナリ式の場合にルートノードを作成する方法を確認することをお勧めします。

于 2012-12-17T20:08:47.710 に答える
3

これは、JJTreehttp : //anandsekar.github.io/writing-an-interpretter-using-javacc/を使用する例です。

于 2014-08-19T17:22:45.913 に答える