工程软件的结果文件由多个页面组成,每页包含一个标题行和一些行数据。每个标题行由以下内容组成:
number)
这样的标题行的一个例子是:

软件在页面后为页面编号分配接下来的六个字符。
解析器工作正常,只有超过99999页的文档可以输出字符串,比如PAGE123456,其中页面和页码之间没有空格(是的,有些软件产生了如此大量的数据)。
我试过的第一个语法是:
grammar F06Reader01;
readF06: dataBlock+ EOF;
dataBlock: pageLine row+;
pageLine: ONE_AT_FIRST_POS ALPNUM* PAGEATPOS ALPNUM NL;
row: ALPNUM* NL ;
PAGEATPOS: P_ATPOS A_ATPOS G_ATPOS E_ATPOS;
P_ATPOS : 'P' {getCharPositionInLine() == 119}?;
A_ATPOS : 'A' {getCharPositionInLine() == 120}?;
G_ATPOS : 'G' {getCharPositionInLine() == 121}?;
E_ATPOS : 'E' {getCharPositionInLine() == 122}?;
ONE_AT_FIRST_POS : '1' {getCharPositionInLine() == 1}?;
ALPNUM : (LETTER | DIGIT)+;
DIGIT: [0-9] ;
LETTER: ~[ \t\n\r\u0030-\u0039]; //everything but DIGITS, NL or WL
NL: '\r'? '\n';
WS : [ \t]+ ->skip;生成的令牌将PAGE231236定义为ALPNUM,因为它创建的令牌大于页面。
在发现此问题后,我修改了g4文件,以添加一个词法模式(PAGENUM),以便在lexer找到页面时激活它,但这种情况没有发生,而lexer仍然生成ALPNUM标记。
下面是lexer文件:
lexer grammar ModeTest01Lexer;
PAGEATPOS: P_ATPOS A_ATPOS G_ATPOS E_ATPOS -> mode(PAGENUM);
P_ATPOS : 'P' {getCharPositionInLine() == 119}?;
A_ATPOS : 'A' {getCharPositionInLine() == 120}?;
G_ATPOS : 'G' {getCharPositionInLine() == 121}?;
E_ATPOS : 'E' {getCharPositionInLine() == 122}?;
ONE_AT_FIRST_POS : '1' {getCharPositionInLine() == 1}?;
ALPNUM : (LETTER | DIGIT)+;
DIGIT: [0-9] ;
LETTER: ~[ \t\n\r\u0030-\u0039]; //everything but DIGITS, NL or WL
NL: '\r'? '\n';
WS : [ \t]+ ->skip;
mode PAGENUM;
NUM : [0-9]+;
WS2 : [ \t]+ ->skip;
NL2: '\r'? '\n' -> mode(DEFAULT_MODE);和分析者:
parser grammar ModeTest01;
options { tokenVocab=ModeTest01Lexer; }
modeTest: dataBlock+ EOF;
dataBlock: pageLine row+;
pageLine: ONE_AT_FIRST_POS ALPNUM* PAGEATPOS NUM NL2;
row: ALPNUM* NL ;这段代码仍然以ALPNUM的形式使用PAGE123456,而不是在找到页面之后切换到PAGENUM模式,如下面的示例及其AST所示:
1 MSC.NASTRAN JOB MARCH 12, 2020 MSC Nastran 11/27/13 PAGE992306
LC01 row
1 MSC.NASTRAN JOB MARCH 12, 2020 MSC Nastran 11/27/13 PAGE 2306
another row of data

发布于 2020-04-08 17:24:46
您可以使用多个lexer模式:
当您在行的开头遇到HEADER_MODE
HEADER_MODE中按下1,然后遇到PAGE,然后按PAGE_NUMBER_MODE (在这种模式下跳过的每个(单个)字符)就像这样:
lexer grammar NastranLexer;
ONE_AT_FIRST_POS
: {getCharPositionInLine() == 0}? '1' -> pushMode(HEADER_MODE)
;
NL
: '\r'? '\n'
;
OTHER
: .
;
mode HEADER_MODE;
HEADER_MODE_PAGE
: 'PAGE' -> pushMode(PAGE_NUMBER_MODE)
;
HEADER_MODE_ANY
: . -> skip
;
mode PAGE_NUMBER_MODE;
PAGE_NUMBER_MODE_NUMBER
: [0-9]+ -> mode(DEFAULT_MODE)
;
PAGE_NUMBER_MODE_SPACE
: [ \t] -> skip
;解析器语法可以如下所示:
parser grammar NastranParser;
options {
tokenVocab=NastranLexer;
}
read
: page* EOF
;
page
: header NL row+
;
header
: ONE_AT_FIRST_POS HEADER_MODE_PAGE PAGE_NUMBER_MODE_NUMBER
;
row
: OTHER* NL
;当你运行这个:
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.ParseTree;
public class Main {
public static void main(String[] args) {
String source = "1 MSC.NASTRAN JOB MARCH 12, 2020 MSC Nastran 11/27/13 PAGE 2306\n" +
"some data\n" +
"1 MSC.NASTRAN JOB MARCH 12, 2020 MSC Nastran 11/27/13 PAGE 2307\n" +
"some more data\n";
NastranLexer lexer = new NastranLexer(CharStreams.fromString(source));
NastranParser parser = new NastranParser(new CommonTokenStream(lexer));
ParseTree parseTree = parser.read();
System.out.println(parseTree.toStringTree(parser));
}
}印刷内容如下:
(read
(page
(header 1 PAGE 2306) \n
(row s o m e d a t a \n))
(page
(header 1 PAGE 2307) \n
(row s o m e m o r e d a t a \n)) <EOF>)(我在上面的输出中添加了一些换行符)
https://stackoverflow.com/questions/61104219
复制相似问题