首页 文章

使用INT和FLOAT进行意外的ANTLR4优化?

提问于
浏览
0

我正在使用 ANTLR 4Clasp 的输出编写解析器 . 典型输出如下:

clasp version 3.0.3
Reading from stdin
Solving...
Answer: 1
bird(a) bird(b) bird(c) penguin(d) bird(d)
Optimization: 7 0
Answer: 2
bird(a) bird(b) bird(c) penguin(d) bird(d) flies_abd(b) flies(b)
Optimization: 6 5
Answer: 3
bird(a) bird(b) bird(c) penguin(d) bird(d) flies_abd(c) flies(c)
Optimization: 2 5
Answer: 4
bird(a) bird(b) bird(c) penguin(d) bird(d) flies_abd(a) flies_abd(c) flies(a) flies(c)
Optimization: 1 10
Answer: 5
bird(a) bird(b) bird(c) penguin(d) bird(d) flies_abd(a) flies_abd(b) flies_abd(c) flies(a) flies(b) flies(c)
Optimization: 0 15
OPTIMUM FOUND

Models       : 5     
  Optimum    : yes
Optimization : 0 15
Calls        : 1
Time         : 0.002s (Solving: 0.00s 1st Model: 0.00s Unsat: 0.00s)
CPU Time     : 0.000s

我必须检查 clasp 是版本 3 所以我写的语法如下:

/**
 * Define a grammar for Clasp 3's output.
 */
grammar Output;

@header {package ac.bristol.clasp.parser;}

output:
    version source solving answer* result separation statistics NEWLINE* EOF;

version: 'clasp version 3.' INT '.' INT NEWLINE;

source: 'Reading from stdin' NEWLINE # sourceSTDIN
    | 'Reading from ' path NEWLINE # sourceFile;

path:
    DRIVE? folder ( BSLASH folder )* filename # pathWindows
    | FSLASH? folder ( FSLASH folder )* filename # pathNIX;

folder:
    LETTER+ # genericFolder
    | DOTDOT # parentFolder
    | DOT # currentFolder;

solving: 'Solving...' NEWLINE;

filename:
    LETTER+ extension?;

extension:
    DOT LETTER*;

answer: 'Answer: ' INT NEWLINE // 
    model? NEWLINE // 
    'Optimization: ' INT ( SPACE INT )* NEWLINE;

model:
    fact ( SPACE fact )*;

fact:
    groundPredicate;

groundTermList:
    groundTerm ( COMMA groundTerm )*;

groundTerm:
    groundCompound | STRING | number | atom; // literal?

groundCompound:
    groundPredicate
    | groundExpression;

groundPredicate:
    IDENTIFIER ( LROUND groundTermList RROUND )?;

groundExpression:
    groundBits AND groundBits
    | groundBits OR groundBits
    | groundBits XOR groundBits;

groundBits:
    groundCompare GT groundCompare
    | groundCompare GE groundCompare
    | groundCompare LT groundCompare
    | groundCompare LE groundCompare;

groundCompare:
    groundItem EQ groundItem
    | groundItem NE groundItem;

groundItem:
    groundFactor PLUS groundFactor
    | groundFactor MINUS groundFactor;

groundFactor:
    groundUnary TIMES groundUnary
    | groundUnary DIVIDE groundUnary
    | groundUnary MOD groundUnary;

groundUnary:
    TILDE groundTerm
    | MINUS groundTerm;

atom:
    IDENTIFIER
    | QUOTED;

number:
    INT
    | FLOAT;

//------------------------------------------------------------------------------

result: 'OPTIMUM FOUND' NEWLINE
    | 'SATISFIABLE' NEWLINE
    | 'UNKNOWN' NEWLINE;

separation:
    NEWLINE;

statistics:
    models optimum? optimization calls time cputime;

models: 'Models       : ' INT SPACE* NEWLINE;

optimum: '  Optimum    : yes' NEWLINE
    | '  Optimum    : no' NEWLINE;

optimization: 'Optimization : ' INT ( SPACE INT )* NEWLINE;
calls: 'Calls        : ' INT NEWLINE;
time: 'Time         : ' FLOAT 's (Solving: ' FLOAT 's 1st Model: ' FLOAT 's Unsat: ' FLOAT 's)' NEWLINE;
cputime: 'CPU Time     : ' FLOAT 's';

//------------------------------------------------------------------------------

AND:       '&';
BSLASH:    '\\';
COLON:     ':';
COMMA:     ',';
DIVIDE:    '/';
DOT:       '.';
DOTDOT:    '..';
EQ:        '==';
FSLASH:    '/';
GE:        '>=';
GT:        '>';
LE:        '<=';
LROUND:    '(';
LT:        '<';
MINUS:     '-';
MOD:       '%';
NE:        '!=';
OR:        '?';
PLUS:      '+';
RROUND:    ')';
SEMICOLON: ';';
SPACE:     ' ';
TILDE:     '~';
TIMES:     '*';
XOR:       '^';

DRIVE:      ( LOWER | UPPER ) COLON BSLASH?;
IDENTIFIER: LOWER FOLLOW*;
INT:        DIGIT+;
FLOAT:      DIGIT+ DOT DIGIT+;
NEWLINE:    '\r'? '\n';
QUOTED:     '\'' ( ~[\'\\] | ESCAPE )+? '\'';
STRING:     '"' ( ~["\\] | ESCAPE )+? '"';

fragment DIGIT:      [0] | NONZERO;
fragment ESCAPE:     '\\' [btnr"\\] | '\\' [0-3]? [0-7]? [0-7] | '\\' 'u' [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F];
fragment FOLLOW:     LOWER | UPPER | DIGIT | UNDERSCORE;
fragment LETTER:     LOWER | UPPER | DIGIT | SPACE;
fragment LOWER:      [a-z];
fragment NONZERO:    [1-9];
fragment UNDERSCORE: [_];
fragment UPPER:      [A-Z];

请注意,输入流的某些部分没有规则,因为我想检查每个字符 . 另请注意,我有一个 INT 的终端规则,一个用于 FLOATINT 是在 FLOAT 之前定义的, FLOAT 是在Prolog中定义的 .

解析上述示例第一行的规则如下:

version: 'clasp version 3.' INT '.' INT NEWLINE;

因为我必须检查所使用的 clasp 主要版本号是否为3,而不是我必须使用读取次要版本号,点,内部版本号和换行符(不含空格或任何内容)的其余行 . 不幸的是,我收到以下警告消息,这让我觉得ANTLR将次要版本号,点和内部版本号识别为 FLOAT

line 1:16 mismatched input '0.3' expecting INT

你能解释一下发生了什么吗?
我假设我不应该做些什么吗?
或者是 ANTLR 正在应用不需要的优化?

1 回答

  • 0

    ANTLR将您的输入分解为令牌,并且仅在解析令牌之后 . 您在解析器规则中使用 'clasp version 3.' 隐式定义了与该文本字符串匹配的匿名标记 . 该标记后面的文本以 0.0 开头,它与float匹配 . 词法分析器不知道解析器在那时将处于 version 规则中;它只选择从当前位置开始的最长令牌,而 0.0 作为 FLOAT 长于 0 作为 INT . 我推荐以下内容:

    • 将语法分成 parser grammar OutputParser;lexer grammar OutputLexer; 在解析器语法中,使用 tokenVocab 选项指示哪个词法分析器定义了您的标记 . 这种分离将迫使您为语法使用的所有内容定义真实令牌 .
    options {
      tokenVocab = OutputLexer;
    }
    
    • 使用 FLOAT 而不是 INT '.' INT ,或者创建一个新令牌来表示版本:
    VERSION
      : DIGIT+ DOT DIGIT+ DOT DIGIT+
      ;
    

相关问题