首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ANTLR4,将较短的字符序列与词汇模式匹配

ANTLR4,将较短的字符序列与词汇模式匹配
EN

Stack Overflow用户
提问于 2020-04-08 15:21:49
回答 1查看 146关注 0票数 1

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

number)

  • NL

  1. 字符“1”位于行
  2. 的第一个位置--一些字母数字字符(一般数据不被解析)在
  3. 数字字符串的第122个位置(页
  4. )中的
  5. 字符串'PAGE‘

这样的标题行的一个例子是:

软件在页面后为页面编号分配接下来的六个字符。

解析器工作正常,只有超过99999页的文档可以输出字符串,比如PAGE123456,其中页面和页码之间没有空格(是的,有些软件产生了如此大量的数据)。

我试过的第一个语法是:

代码语言:javascript
复制
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文件:

代码语言:javascript
复制
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);

和分析者:

代码语言:javascript
复制
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所示:

代码语言:javascript
复制
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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-04-08 17:24:46

您可以使用多个lexer模式:

当您在行的开头遇到HEADER_MODE

  • when时,您在HEADER_MODE中按下1,然后遇到PAGE,然后按PAGE_NUMBER_MODE (在这种模式下跳过的每个(单个)字符)

就像这样:

代码语言:javascript
复制
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
   ;

解析器语法可以如下所示:

代码语言:javascript
复制
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
 ;

当你运行这个:

代码语言:javascript
复制
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));
    }
}

印刷内容如下:

代码语言:javascript
复制
(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>)

(我在上面的输出中添加了一些换行符)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61104219

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档