ANTLR初学者=>;语法问题

ANTLR初学者=>;语法问题,antlr,grammar,Antlr,Grammar,我是一个使用ANTLR的初学者。我只是出于测试目的做了以下工作,并试图了解它的工作方式和产生错误的方式: INTEGER_数:('0'..'9')+ integer\u编号:integer\u编号 decimal_number:“整数_number.”“整数_number”)(“整数_number”) 正则数:十进制数|整数|数 关于“常规编号”规则,我有以下警告:决策可以匹配输入,例如“整数编号”。“整数编号”使用多个选项:1、2 因此,该输入的备选方案2被禁用 这到底意味着什么 好的,我已

我是一个使用ANTLR的初学者。我只是出于测试目的做了以下工作,并试图了解它的工作方式和产生错误的方式:

INTEGER_数:('0'..'9')+
integer\u编号:integer\u编号
decimal_number:“整数_number.”“整数_number”)(“整数_number”)
正则数:十进制数|整数|数

关于“常规编号”规则,我有以下警告:决策可以匹配输入,例如“整数编号”。“整数编号”使用多个选项:1、2 因此,该输入的备选方案2被禁用

这到底意味着什么


好的,我已经编辑了这篇文章,包括重现这个错误的代码

程序:(价格)*

INTEGER_数:('0'..'9')+
INFO_PRICE:“旧价格”
分数编号:'1/16''1/8''3/16''1/4''5/16''3/8''7/16''1/2''9/16''5/8''11/16''3/4''13/16''7/8''15/16'
货币:“欧元”“美元”“英镑”

integer\u编号:integer\u编号
十进制数:(整数?')整数
分数:(整数(“)+)?分数_数
正则数:十进制数|整数|数
数值_数:正则_数|分数_数
non_numeric_number:INFO_PRICE((“”)*)(“+”|“-”)((“”)*)(numeric_number)((“”)*)货币

价格:数字|非数字|

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

我们知道的错误是这个

错误(201):/ANTLR-Tuto 1/src/Test.g:37:2:以下选项永远无法匹配:2
|--->:十进制数|整数|数

您发布的错误意味着有两条规则与某些输入匹配,在您的案例中,输入
整数。\n整数
。然而,正如巴特评论的那样,你发布的语法没有这个问题。您确定错误来自您发布的内容吗?

如评论中所述,您发布的语法没有问题

您提到的错误发生在以下语法中:

grammar Test;

regular_number
  :  decimal_number
  |  integer_number
  ;

integer_number
  :  INTEGER_NUMBER
  ;

decimal_number
  :  integer_number '.' integer_number
  |  '.' integer_number
  |  integer_number                      // <- I added this one
  ;

INTEGER_NUMBER 
  :  '0'..'9'+ 
  ;

编辑 在
常规\u编号
规则中,字符串
“123.456”
可以解析为:

integer_number decimal_number
123            .456
或作为:

decimal_number
123.456
为什么不在lexer中定义一个十进制数:

DECIMAL_NUMBER
  :  INTEGER_NUMBER '.' INTEGER_NUMBER
  |  '.' INTEGER_NUMBER
  ;
?

这应该可以解决这个问题

不过,还有更多问题:

numerical_number 
  :  fraction_number
  |  regular_number
  ;
当上面的规则试图处理像
“2 1/8”
这样的输入时,其中的
2
可能是
分数
的一部分,包括
1/8
,但也可以作为
常规
后接
分数
处理

另外,您不应该在解析器规则中定义空格,您已经将它们放在lexer中的隐藏通道上,因此解析器不会“看到”它们

话虽如此,这将是一种可能的替代语法,可能满足您的需求:

program 
  :  price* EOF
  ;

price 
  :  numerical_number 
  |  non_numerical_number
  ;

numerical_number
  :  FRACTION_NUMBER
  |  DECIMAL_NUMBER
  |  INTEGER_NUMBER
  ;

non_numerical_number 
  :  INFO_PRICE ('+' | '-') (INTEGER_NUMBER FRACTION_NUMBER | numerical_number) CURRENCY
  ;

DECIMAL_NUMBER
  :  INTEGER_NUMBER '.' INTEGER_NUMBER
  |  '.' INTEGER_NUMBER
  ;

FRACTION_NUMBER 
  :  '1/16' | '1/8' | '3/16' | '1/4' | '5/16' | '3/8' | '7/16' | '1/2' | 
     '9/16' | '5/8' | '11/16' | '3/4' | '13/16' | '7/8' | '15/16'
  ;

INTEGER_NUMBER  
  :  '0'..'9'+
  ;

INFO_PRICE
  : 'OLD PRICE'
  ;

CURRENCY
  : 'EUR' | 'USD' | 'GBP'
  ;

WS 
  :  (' ' | '\t' | '\f' | '\r' | '\n')+ {$channel=HIDDEN;}
  ;
编辑二 另外,您不应该在解析器规则中定义空格,您已经 把它们放在lexer的隐藏通道上,这样它们就不会被“看到” 由解析器执行

问题是,lexer将如何发挥作用 例如,甜菜蛋白1011 1/16和101 11/16

当遇到(子)字符串
1011 1/16
时,
1011
被标记为
整数
,空间被放在隐藏通道上(因此在传递给解析器的令牌流中不存在),
1/16
被标记为
分数

对于
101 11/16
同样适用:
101
整数
11/16
分数

要强调的是:当您在不同的通道(如隐藏通道)上放置空格和换行符时,它们不会出现在解析器操作的令牌流中。所以在解析器规则中使用这些标记是没有意义的:它们永远不会被匹配


HTH

你发布的语法没有问题。在命令行上生成lexer和解析器,并使用ANTLRWorks(1.4),不会产生您发布的错误。之后还有其他规则吗?我怀疑有。您正在测试令牌的开始和结束吗?除了这个问题,您还可以更改
十进制数:(整数。'integer_number')('integer_number')到<代码>十进制数:(整数?。“整数”):同样的东西,但它更短。谢谢你的回答,你没事,我从我的示例中提取了这段代码,因为警告发布在这一行上。事实上,这个警告似乎是因为另一条规则而出现的。。。我将尝试查看哪一个并发布代码。感谢您的回答,您也很好,我从示例中提取了这段代码,因为警告发布在这一行上。事实上,这个警告似乎是因为另一条规则而出现的。。。我会试着看看是哪一个,然后把代码发出去。@BlackLabrador,不客气。我想你现在知道什么时候会发生这样的错误了吧?如果你仍然不确定你的语法错误在哪里,请编辑你的原始问题并发布整个语法。谢谢巴特,我已经编辑了这篇文章,并试图把产生错误的版本放进去。非常感谢你的精彩报道!你的评论非常精确和宝贵!!!!此外,您不应该在解析器规则中定义空格,您已经将它们放在lexer中的隐藏通道上,因此解析器不会“看到”它们。=>问题是,lexer将如何在10111/16和10111/16之间产生差异?嗨,Jorn,显然是warni
program 
  :  price* EOF
  ;

price 
  :  numerical_number 
  |  non_numerical_number
  ;

numerical_number
  :  FRACTION_NUMBER
  |  DECIMAL_NUMBER
  |  INTEGER_NUMBER
  ;

non_numerical_number 
  :  INFO_PRICE ('+' | '-') (INTEGER_NUMBER FRACTION_NUMBER | numerical_number) CURRENCY
  ;

DECIMAL_NUMBER
  :  INTEGER_NUMBER '.' INTEGER_NUMBER
  |  '.' INTEGER_NUMBER
  ;

FRACTION_NUMBER 
  :  '1/16' | '1/8' | '3/16' | '1/4' | '5/16' | '3/8' | '7/16' | '1/2' | 
     '9/16' | '5/8' | '11/16' | '3/4' | '13/16' | '7/8' | '15/16'
  ;

INTEGER_NUMBER  
  :  '0'..'9'+
  ;

INFO_PRICE
  : 'OLD PRICE'
  ;

CURRENCY
  : 'EUR' | 'USD' | 'GBP'
  ;

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