当前位置: 首页 > 知识库问答 >
问题:

ANLTR 4语法

汤承德
2023-03-14

我试图开发一个语法来解析使用ANTLR4的DSL(第一次尝试使用它)。语法本身在某种意义上有点类似于SQL

它应该能够解析如下命令:

select type1.attribute1 type2./xpath_expression[@id='test 1'] type3.* from source1 source2 
fromDate 2014-01-12T00:00:00.123456+00:00 toDate 2014-01-13T00:00:00.123456Z
where (type1.attribute2 = "XX" AND 
    (type1.attribute3 <= "2014-01-12T00:00:00.123456+00:00" OR
    type2./another_xpath_expression = "YY"))

编辑:我已经按照[lucas_trzesniewski]的建议更新了语法切换CHAR,符号和数字的片段,但我没有设法得到改进。附加的是特伦斯建议的解析树。我还在控制台中得到了以下内容(我越来越困惑...

warning(125): API.g4:16:8: implicit definition of token 'CHAR' in parser
warning(125): API.g4:20:31: implicit definition of token 'SYMBOL' in parser
line 1:12 mismatched input 'p' expecting {'.', NUMBER, CHAR, SYMBOL}
line 1:19 mismatched input 't' expecting {'.', NUMBER, CHAR, SYMBOL}
line 1:27 mismatched input 'm' expecting {'.', NUMBER, CHAR, SYMBOL}
line 1:35 mismatched input '@' expecting {NUMBER, CHAR, SYMBOL}
line 1:58 no viable alternative at input 'm'
line 3:13 no viable alternative at input '(deco.m'

我能够将大部分语法放在一起,但它无法正确匹配所有标记,因此导致根据输入的复杂性进行不正确的解析。在我看来,通过在互联网上浏览,主要原因是词法分析器选择了最长的匹配序列,但即使尝试了几次重写词法分析器和语法规则,我也无法获得一个健壮的集合。

下面是我的语法和一些测试用例。指定规则的正确方法是什么?我应该使用lexer模式吗?

语法

语法接口;

get : K_SELECT  (((element) )+ | '*') 
      'from'  (source )+
      ( K_FROM_DATE dateTimeOffset )? ( K_TO_DATE dateTimeOffset )?
      ('where'  expr )?  
      EOF
    ;


element     : qualifier DOT attribute; 
qualifier   : 'raw' | 'std' | 'deco' ;
attribute   : ( word | xpath | '*') ;

word  : CHAR (CHAR | NUMBER)*;

xpath   : (xpathFragment+);
xpathFragment
    : '/' ( DOT | CHAR | NUMBER | SYMBOL )+ 
    | '[' (CHAR | NUMBER | SYMBOL )+ ']'
    ;

source      : ( 'system1' | 'system2' | 'ALL')  ; // should be generalised.


date        : (NUMBER MINUS NUMBER MINUS NUMBER) ;
time        : (NUMBER COLON NUMBER (COLON NUMBER ( DOT NUMBER )?)? ( 'Z' | SIGN (NUMBER COLON NUMBER )));
dateTimeOffset : date 'T' time;

filter      : (element OP value) ;
value       : QUOTE .+? QUOTE ;

expr
    :  filter 
    | '(' expr 'AND' expr ')'
    | '(' expr 'OR'  expr ')'
    ;


K_SELECT    : 'select';
K_RANGE     : 'range';
K_FROM_DATE : 'fromDate';
K_TO_DATE   : 'toDate'  ;


QUOTE : '"' ;
MINUS : '-';
SIGN  : '+' | '-';
COLON : ':';
COMMA : ',';
DOT   : '.';
OP    : '=' | '<' | '<=' | '>' | '>=' | '!=';


NUMBER : DIGIT+;

fragment DIGIT : ('0'..'9');
fragment CHAR   : [a-z] | [A-Z] ;
fragment SYMBOL : '@' | [-_=] | '\'' | '/' | '\\' ;

WS    : [ \t\r\n]+ -> skip ;
NONWS : ~[ \t\r\n];

测试1

select raw./priobj/tradeid/margin[@id='222'] deco.* deco.marginType from system1 system2
fromDate 2014-01-12T00:00:00.123456+00:00 toDate 2014-01-13T00:00:00.123456Z 
where ( deco.marginType >= "MV" AND ( ( raw.CretSysInst = "RMS_EXODUS" OR deco.ExtSysNum <= "1234" ) OR deco.ExtSysStr = "TEST Spaced" ) )

测试2

select * from ALL

测试3

select deco./xpath/expr/text() deco./xpath/expr[a='3' and b gt '6] raw.* from ALL where raw.attr3 = "myvalue"

共有1个答案

孙熠彤
2023-03-14

这: 数字 : ('0'..'9');应该是一个片段。这同样适用于此:字符:[a-z] |[A-Z] ;.这样,您可以编写数字:字符;单词:字符(字符|号码)*;

原因很简单:你想在解析器中处理有意义的标记,而不是部分单词。把词法分析器想象成在有意义的点“剪切”输入文本的东西。稍后,你想处理完整的单词,而不是单个字符。所以想想在哪里进行这些剪切最有意义。

现在,正如ANTLR大师所指出的那样,要调试您的问题,请转储解析树并查看发生了什么。

 类似资料:
  • 主要内容:1. 生产参数,2. 缩进空间,3. 分离空间,4. 忽略行前缀,5. 折叠线在本章中,将了解YAML中语法原语的以下几个方面 - 生产参数 缩进空间 分离空间 忽略的行前缀 折叠线 下面来详细地了解每个方面。 1. 生产参数 生产参数包括一组参数以及在特定生产中使用的允许值范围。 YAML中使用以下生产参数列表 - 缩进 它由字符或表示字符流取决于其中包含的块的缩进级别。 许多生产都参数化了这些功能。 上下文 它由表示,YAML支持两组上下文:块样式和流样式。 样式 它由

  • 这一部分将 Rust 拆成小的部分,每一部分对应一个概念。 如果你想要自底向上的学习 Rust,按顺序阅读这一部分将会有很大帮助。 这些部分也组成了一个对各种概念的参考,所以如果你阅读其它教程并发现一些迷惑的问题,你可以在这里找到一些解释。

  • 我想用javascript/php实现法语、俄语等外语的拼写更正。对于英语拼写检查器,我可以使用编辑距离算法从英语词典中检索单词(词典是使用Trie构建的),并返回最频繁的单词。我还找到了关于这方面的文章,例如。http://stevehanov.ca/blog/index.php?id=114.我认为对于外语来说,同样的方法也是有用的。 我相信必须为不同的语言提供API,但我不想在我的应用程序中

  • 主要内容:第一个Dart语序,Dart命令行选项,启用检查模式,Dart标识符,Dart关键字,Dart注释,Dart面向对象编程语法定义了一组用于编写程序的规则。每种语言规范都定义了自己的语法。Dart程序代码由以下组成 - 变量和运算符 类 函数 表达式和编程构造 决策和循环结构 注解 库和包 类型定义 数据结构 - 集合/泛型 第一个Dart语序 函数是Dart中的预定义方法。此方法充当应用程序的入口点。Dart脚本需要方法来执行。是一个预定义的函数,它将指定的字符串或值打印到标准输出(即

  • 主要内容:R命令提示符,R脚本文件,注释学习一个新编程语言的惯例是什么?,当然是编写一个“Hello,World!”,下面我们将演示如何使用R编程编写一个“Hello,World!”程序。根据需要,您可以在R命令提示符下编程,也可以使用R脚本文件编写程序。 R命令提示符 当安装好了R开发环境以后,那么通过在命令提示符下键入以下命令,就可以启动R命令提示符 - 或者,在Windows系统下 - 这将启动R解释器,您将获得一个提示您可以在以

  • 上一章节我们已经了解了 Go 语言的基本组成结构,本章节我们将学习 Go 语言的基础语法。 Go 标记 Go 程序可以由多个标记组成,可以是关键字,标识符,常量,字符串,符号。如以下 GO 语句由 6 个标记组成: fmt.Println("Hello, World!") 6 个标记是(每行一个): 1. fmt 2. . 3. Println 4. ( 5. "Hello, World!"

  • 顾名思义,一个命令式语言是由一个个“命令”为单元组成,不过一般很少用命令这个词,而是细分一下,比较低级的语言用指令(instruction),高低的语言一般认为是一个语句(statement,以后简称stmt),词法分析只将一段高级语言代码分解成一个个词,接下来还要做语句层面的分析,最终目标是生成抽象语法树(ast) 代码: a = 1; s = 0; while (a <= 100)

  • 问题内容: 为什么Python在第9行的简单语句中给我一个语法错误? Python的版本是: 问题答案: 在Python 3中,print是一个函数,您需要像这样调用它。