1

これが今日の私の 1000 番目の質問のようです :) 文法の完成に近づいています。前置演算子と中置演算子が同じ記号を共有している場合に問題が発生します。MathML として知られるマークアップ言語を解析しています...

grammar MathMLOperators;

options 
{
  output = AST;
  backtrack = true;
  memoize = true;
}

tokens
{
  DOCUMENT; // The root of the parsed document.
  GROUP;

  OP; // any operator
  PREFIX_OP; // a prefix operator.
  INFIX_OP; // an infix operator.
  POSTFIX_OP; // a postfix operator.
  NON_INFIX_OP; // a non-infix operator
}

// Start rule.
public document :  math+ -> ^(DOCUMENT math+);

inFixTag : TAG_START_OPEN MO  TAG_CLOSE ('-' | '+' | '=') TAG_END_OPEN MO TAG_CLOSE -> ^(INFIX_OP);

preFixTag : TAG_START_OPEN MO TAG_CLOSE ('+' | '-') TAG_END_OPEN MO TAG_CLOSE -> ^(PREFIX_OP);

// Use semantic predicate to only allow postfix expressions when at the end of an mrow.
postFixTag : TAG_START_OPEN MO TAG_CLOSE ('!' | '^') TAG_END_OPEN MO {input.LT(1).getType() == TAG_CLOSE && input.LT(2).getType() == TAG_END_OPEN && input.LT(3).getType() == MROW && input.LT(4).getType() == TAG_CLOSE}? TAG_CLOSE -> ^(POSTFIX_OP);

nonInfixTag : TAG_START_OPEN MO TAG_CLOSE ('!' | '^') TAG_END_OPEN MO TAG_CLOSE {$expressionList::count++;} -> ^(OP);

opTag: TAG_START_OPEN MO TAG_CLOSE  ('-' | '+' | '^' |'=')  TAG_END_OPEN MO TAG_CLOSE -> ^(NON_INFIX_OP);

//Expressions

infixExpression:  grouping (inFixTag^ grouping)*;
grouping : nestedExpression+ -> ^(GROUP nestedExpression+);

prefixExpression : /* check that it's the first in the mrow*/ {$expressionList::count == 0}? (preFixTag^ (primaryExpression | nonInfixTag)) {$expressionList::count++;};

postfixExpression : (primaryExpression | prefixExpression| nonInfixTag) (postFixTag^)? ;

expressionList scope {int count} @init{$expressionList::count = 0;} :  (infixExpression | opTag)+;

nestedExpression :  postfixExpression;

primaryExpression : mrow | mn;

math : TAG_START_OPEN root=MATH TAG_CLOSE expressionList TAG_END_OPEN MATH TAG_CLOSE -> ^($root expressionList);

mrow : TAG_START_OPEN root=MROW TAG_CLOSE expressionList? TAG_END_OPEN MROW TAG_CLOSE -> ^($root expressionList?);

mn: TAG_START_OPEN root=MN TAG_CLOSE INT TAG_END_OPEN MN TAG_CLOSE -> ^($root INT);

MATH : 'math'; // root tag
MROW : 'mrow'; // row
MO   : 'mo'; // operator
MN   : 'mn'; // number

TAG_START_OPEN : '<';
TAG_END_OPEN : '</' ;
TAG_CLOSE : '>';
TAG_EMPTY_CLOSE : '/>';

INT :   '0'..'9'+;

WS  :  (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;};

これはうまくいきます...

<math>
<mrow>
<mo>-</mo>
<mn>7</mn>
<mo>=</mo>
<mn>8</mn>
</mrow>
</math>

しかし、これは失敗します...

<math>
<mrow>
<mo>-</mo>
<mn>7</mn>
<mo>-</mo>
<mn>8</mn>
</mrow>
</math>

最初の「-」は「プレフィックス」、2 番目は「インフィックス」にする必要があります。デバッガーからは、ルールがループしていて、一致しない場合でもgrouping親ルールに戻らないようです。infixExpression

どこかで EBNF 演算子が間違っていることは確かですが、どれが間違っているのかわかりません。C などの言語で見られる標準的な式の入れ子パターンに従おうとしましたが、これは解析する言語としては珍しいものです。

4

1 に答える 1

1

文法を送っていただけませんか...

これが、クリーンアップした後の文法です。

警告:質問のパーサーがどのように動作するかを説明できないので(したがって、クリーンアップします)、元のパーサーから意図せずに壊れた/修正したものがわかりません-ASTまたはパーサーが間違っていることを教えてくださいそもそも間違っているように見えたので、私には何の意味もありません。;)

grammar MathMLOperators;

options 
{
  output = AST;
  backtrack = true;
  memoize = true;
}

tokens
{
  DOCUMENT; // The root of the parsed document.
  GROUP;
  OP; // any operator
  PREFIX_OP; // a prefix operator.
  INFIX_OP; // an infix operator.
  POSTFIX_OP; // a postfix operator.
  NON_INFIX_OP; // a non-infix operator
}

// Start rule.
public document :  math+ EOF -> ^(DOCUMENT math+);

inFixTag        : (op=MINUS | op=PLUS | op=EQ)  -> INFIX_OP[$op.text];
preFixTag       : (op=MINUS | op=PLUS)          -> PREFIX_OP[$op.text]; 

// Use semantic predicate to only allow postfix expressions when at the end of an mrow.
postFixTag      : (op=BANG | op=CARET) {input.LA(1) == CMROW}?      -> POSTFIX_OP[$op.text];
nonInfixTag     : (op=BANG | op=CARET) {$expressionList::count++;}  -> NON_INFIX_OP[$op.text];
opTag           : (op=MINUS | op=PLUS | op=CARET | op=EQ)           -> OP[$op.text];

//Expressions

infixExpression     : grouping (inFixTag^ grouping)*;
grouping            : nestedExpression+     -> ^(GROUP nestedExpression+);

prefixExpression    : /* check that it's the first in the mrow*/ 
                    {$expressionList::count == 0}? 
                        (preFixTag^ (primaryExpression | nonInfixTag)) 
                        {$expressionList::count++;}
                    ;

postfixExpression   : (primaryExpression | prefixExpression| nonInfixTag) (postFixTag^)? ;

expressionList scope {int count} @init{$expressionList::count = 0;} :  (infixExpression | opTag)+;

nestedExpression    :  postfixExpression;

primaryExpression   : mrow | NUM;

math    : MATH expressionList CMATH -> ^(MATH expressionList);

mrow    : MROW expressionList? CMROW -> ^(MROW expressionList?);

///////   LEXER   ///////

MATH    : TAG_START_OPEN WS* 'math' WS* TAG_CLOSE; // root tag
CMATH   : TAG_END_OPEN WS* 'math' WS* TAG_CLOSE;

MROW    : TAG_START_OPEN WS* 'mrow' WS* TAG_CLOSE; // row
CMROW   : TAG_END_OPEN WS* 'mrow' WS* TAG_CLOSE;

fragment OMO    : TAG_START_OPEN WS* 'mo' WS* TAG_CLOSE; // operator
fragment CMO    : TAG_END_OPEN WS* 'mo' WS* TAG_CLOSE; 

MINUS   : OMO '-' CMO {setText("-");};
PLUS    : OMO '+' CMO {setText("+");};
EQ      : OMO '=' CMO {setText("=");};
BANG    : OMO '!' CMO {setText("!");};
CARET   : OMO '^' CMO {setText("^");};


NUM     : TAG_START_OPEN WS* 'mn' WS* TAG_CLOSE 
            INT 
          TAG_END_OPEN WS* 'mn' WS* TAG_CLOSE 
          {setText($INT.text);}
        ;

fragment TAG_START_OPEN : '<';
fragment TAG_END_OPEN   : '</' ;
fragment TAG_CLOSE      : '>';
fragment TAG_EMPTY_CLOSE: '/>';

INT     :   '0'..'9'+;

WS      :  (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;};

テストケース1:MROWを使用した中置'='

入力:

    <math>
    <mrow>
    <mo>-</mo>
    <mn>7</mn>
    <mo>=</mo>
    <mn>8</mn>
    </mrow>
    </math>

出力:

中置=mrow付き

テストケース2:MROWで「-」を挿入

入力:

    <math>
    <mrow>
    <mo>-</mo>
    <mn>7</mn>
    <mo>-</mo>
    <mn>8</mn>
    </mrow>
    </math>

出力:

中置-mrow付き

テストケース3:MROWなしで「-」を挿入

入力:

    <math>
    <mo>-</mo>
    <mn>7</mn>
    <mo>-</mo>
    <mn>8</mn>
    </math>

出力:

中置-mrowなし

于 2012-12-22T02:14:12.087 に答える