1

私はANTLRと次の文法を使用しています:

grammar QuickBasic;

options 
{
    language = 'CSharp2';
    output = AST;
}

parse
    :    block EOF
    ;

block
    :    (labelStatement | labeledStatement | statement)*
    ;

labelStatement
    :    label ':' -> ^(label)
    ;

labeledStatement
    :    label statement -> ^(label statement)
    ;

statement
    :    assignment
    ;

assignment
    :    IDENTIFIER '=' value -> ^('=' IDENTIFIER value)
    ;

value
    :    (IDENTIFIER | constant)
    ;

constant 
    :    (STRING | INTEGER | REAL)
    ;

label
    :    (ALPHANUMERIC)+
    ;

IDENTIFIER
    :    LETTER (ALPHANUMERIC)*
    ;

REAL
    :    (INTEGER '.' NATURAL)
    ;

INTEGER
    :    ('-')? NATURAL
    ; 

SPACE
    :    (' ' | '\t' | '\r' | '\n' | '\u000C') {Skip();} 
    ;

STRING
    :    '"' ('""' | ~'"')* '"'
    ;

fragment NATURAL
    :    (DIGIT)+
    ;   

fragment ALPHANUMERIC
    :    (DIGIT | LETTER)
    ;

fragment DIGIT
    :    '0'..'9'
    ;

fragment LETTER
    :    ('a'..'z' | 'A'..'Z')
    ;

これにより、次のファイルを解析しようとしています。

PI = 3.141592
CALC:
100 A = 1

次に何が起こるかというと、「CALC:」という行はラベルである必要がありますが、ステートメントとして解析しようとすると、「=」が必要であると入力「:」が一致しないというエラーが表示されます。

4

2 に答える 2

2

あなたのlabelルールは間違っています:

label
    :    (ALPHANUMERIC)+
    ;

はフラグメントレクサールールであるためALPHANUMERIC、パーサールールでは使用できず、他のレクサールールでのみ使用できます。レクサーは次のトークンのみを生成します:、、、IDENTIFIERおよび(INTEGERおよびパーサールール内のリテラルトークンなど):これらをパーサールールで使用できる唯一のレクサールールにします。REALSTRING'.'

また、一意のルートが1つしかないASTのみを作成する必要があります。両方のルートを作成しようとしていますがlabelStatementlabeledStatement他のパーサールールと区別できません。ツリーウォーカー(ANTLRのツリーウォーカーまたは独自のツリーウォーカー)がそのようなASTのルートに遭遇したときに問題が発生するようにします。 。LABEL(架空の)トークンを作成LABELED_STATして、それらをASTのルートにする方がはるかに優れています。

...

tokens 
{
    LABEL;
    LABELED_STAT;
}

parse
    :    block EOF
    ;

...

labelStatement
    :    label ':' -> ^(LABEL label)
    ;

labeledStatement
    :    label statement -> ^(LABELED_STAT label statement)
    ;

...

label
    :    IDENTIFIER
    |    INTEGER
    ;

これにより、次のASTが作成されます。

ここに画像の説明を入力してください

于 2012-05-29T07:53:09.627 に答える
0

Skip() の代わりに小文字の skip() を使用してみてください。複数のスペースを許可するには、このようなものを使用してください

SPACE
    :    (' ' | '\t' | '\u000C' | '\n' | '\r' )+ {skip();} 
    ;
于 2012-05-29T05:02:17.117 に答える