ANTLR 隐式乘法

2024-01-20

我是 ANTLR 的新手,我正在尝试扩展所提供的简单计算器的示例here https://stackoverflow.com/a/1932664。具体来说,我尝试添加一些简单的函数、负数等,以熟悉 ANTLR。然而,我在尝试实现“隐式”乘法时遇到了一些问题(例如,3cos(2)sin(2) 将被解释为 3*cos(2)*sin(2))。

我在 Stack Overflow 上发现了一个有同样问题的问题(here https://stackoverflow.com/q/2398118/1933612)。该问题的解决方案的一般形式看起来像我自己发现的,所以我不确定我的问题出在哪里。

我的语法如下。如果没有| p2 = signExpr {$value *= $p2.value;}行(最后一行multiplicationExpr),根据我的测试,一切似乎都工作正常。当我添加这一行并运行它时antlr,我收到以下错误:

error(211): calculator.g:24:3: [fatal] rule multiplicationExpr has non-LL(*) decision due to recursive rule invocations reachable from alts 3,4.  Resolve by left-factoring or using syntactic predicates or using backtrack=true option.
warning(200): calculator.g:24:3: Decision can match input such as "'-' FLOAT" using multiple alternatives: 3, 4
As a result, alternative(s) 4 were disabled for that input

启用backtrack导致我的一些(正常工作的)测试表达式计算错误。此外,警告还谈到了替代方案 3 和 4multiplicationExpr,但我在该块中只有三种选择,这让我很困惑。

有人能指出我的语法错误吗?如下所示?

grammar calculator;

eval    returns [double value]
        : exp = additionExpr    {$value = $exp.value;}
        ;

additionExpr    returns [double value]
        :               m1 = multiplicationExpr {$value = $m1.value;}
                ( '+'   m2 = multiplicationExpr {$value += $m2.value;}
                | '-'   m2 = multiplicationExpr {$value -= $m2.value;}
                )*
        ;

multiplicationExpr      returns [double value]
        :               p1 = signExpr   {$value = $p1.value;}
                ( '*'   p2 = signExpr   {$value *= $p2.value;}
                | '/'   p2 = signExpr   {$value /= $p2.value;}
                |       p2 = signExpr   {$value *= $p2.value;}
                )*
        ;

signExpr        returns [double value]
        :       (       '-' a = funcExpr        {$value = -1*$a.value;}
                ) | (   a = funcExpr            {$value = $a.value;}
                )
        ;

funcExpr        returns [double value]
        :       (       'cos' s = signExpr      {$value = Math.cos($s.value);}
                ) | (   'sin' s = signExpr      {$value = Math.sin($s.value);}
                ) | (   s = powExpr             {$value = s;}
                )
        ;

powExpr returns [double value]
        :               s1 = atomExpr   {$value = $s1.value;}
                ( '^'   s2 = signExpr   {$value = Math.pow($value, $s2.value);}
                )?
        ;

atomExpr        returns [double value]
        :       f = FLOAT                       {$value = Double.parseDouble($f.text);}
        |       '(' exp = additionExpr ')'      {$value = $exp.value;}
        ;

FLOAT
    :   ('0'..'9')+ ('.' ('0'..'9')*)? EXPONENT?
    |   '.' ('0'..'9')+ EXPONENT?
    ;

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

fragment
EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;

新的一年,新版本:-)

由于您是 ANTLR 的新手,并且现在已经看到 v3 的一些歧义问题,您一定会欣赏 v4 的强大功能。以下是a解决方案(我是 v4 的新手)将计算保持在表达式级别,但展示了使用 ANTLR4 描述表达式是多么简单。

grammar Calculator;

progr : eval+ EOF ;

eval 
    :   mult ';' {System.out.println($eval.text + " -> " + $mult.value);}
    ;

mult    returns [double value]
    :   e1 = expr                  {$value = $e1.value;}
    |   e1 = expr e2 = mult        {$value = $e1.value * $e2.value;}
    ;

expr    returns [double value]
    :   e1 = expr '^'<assoc=right> e2 = expr   {$value = Math.pow($e1.value, $e2.value);}
    |   '-' e1 = expr              {$value = -1 * $e1.value;}
    |   e1 = expr '*' e2 = expr    {$value = $e1.value * $e2.value;}
    |   e1 = expr '/' e2 = expr    {$value = $e1.value / $e2.value;}
    |   e1 = expr '+' e2 = expr    {$value = $e1.value + $e2.value;}
    |   e1 = expr '-' e2 = expr    {$value = $e1.value - $e2.value;}
    |   'cos' s = expr             {$value = 2; System.out.println("cos" + $s.text + "=2");} // {$value = Math.cos($s.value);}
    |   'sin' s = expr             {$value = 5; System.out.println("sin" + $s.text + "=5");} // {$value = Math.sin($s.value);}
    |   FLOAT                      {$value = Double.parseDouble($FLOAT.text); System.out.println("FLOAT=" + $FLOAT.text);}
    |   '(' FLOAT ')'              {$value = $expr.value;} // just for demo, to avoid printing FLOAT parameters
    |   '(' e1 = expr ')'          {$value = $e1.value; System.out.println("expr(" + $e1.text + ")=" + $e1.value);}
    ;

FLOAT
    :   DIGIT+ ( '.' DIGIT* )? EXPONENT?
    |   '.' DIGIT+ EXPONENT?
    ;

WS  :   [ \t\r\n] -> channel(HIDDEN)
    ;

fragment DIGIT    : [0-9] ;
fragment EXPONENT : [Ee] ( '+' | '-' )? DIGIT+ ;

文件输入.txt:

3cos(2)sin(6);
4cos(2)cos(8)sin(6);
sin(1)sin(6);
sin(1)sin(6)cos(8)10sin(8);
sin(1)5cos(6)3;
2^8;
3*-12;
55/sin(0);
55/(2 + 3);

执行 :

$ echo $CLASSPATH
.:/usr/local/lib/antlr-4.0b3-complete.jar
$ alias
alias antlr4='java -jar /usr/local/lib/antlr-4.0b3-complete.jar'
alias grun='java org.antlr.v4.runtime.misc.TestRig'
$ antlr4 Calculator.g4 
$ javac Calculator*.java
$ grun Calculator progr input.txt 
FLOAT=3
cos(2)=2
sin(6)=5
3cos(2)sin(6); -> 30.0
FLOAT=4
cos(2)=2
cos(8)=2
sin(6)=5
4cos(2)cos(8)sin(6); -> 80.0
sin(1)=5
sin(6)=5
sin(1)sin(6); -> 25.0
sin(1)=5
sin(6)=5
cos(8)=2
FLOAT=10
sin(8)=5
sin(1)sin(6)cos(8)10sin(8); -> 2500.0
sin(1)=5
FLOAT=5
cos(6)=2
FLOAT=3
sin(1)5cos(6)3; -> 150.0
FLOAT=2
FLOAT=8
2^8; -> 256.0
FLOAT=3
FLOAT=12
3*-12; -> -36.0
FLOAT=55
sin(0)=5
55/sin(0); -> 11.0
FLOAT=55
FLOAT=2
FLOAT=3
expr(2 + 3)=5.0
55/(2 + 3); -> 11.0

Notes :
1)我给 cos 和 sin 赋予了固定值,以便能够轻松验证计算。
2)使用 -diagnostics 运行,您将看到不明确的消息:

$ grun Calculator progr -diagnostics input.txt 
FLOAT=3
line 1:6 reportAttemptingFullContext d=2, input='(2)'
line 1:6 reportAmbiguity d=2: ambigAlts={5, 6}, input='(2)'

这是因为我添加了以下行:

    |   '(' FLOAT ')'              {$value = $expr.value;} // just for demo

良好地打印(避免将参数打印为 cos/sin)。这是有歧义的'(' e1 = expr ')'。将其删除,消息就会消失。
3) 查看 ANTLR4 如何标记化 (-tokens) 和解析 (-trace) :

grun Calculator progr -tokens -diagnostics -trace input.txt

4) 站点:http://antlr4.org http://antlr4.org
5)书:http://pragprog.com/book/tpantlr2/the-definitive-antlr-4-reference http://pragprog.com/book/tpantlr2/the-definitive-antlr-4-reference
6) 在 OS X 上安装 4.0b3 :http://forums.pragprog.com/forums/206/topics/11231 http://forums.pragprog.com/forums/206/topics/11231
7)SO过滤器:https://stackoverflow.com/questions/tagged/antlr4 https://stackoverflow.com/questions/tagged/antlr4
8) 组别:https://groups.google.com/forum/#!forum/antlr-discussion https://groups.google.com/forum/#!forum/antlr-discussion

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ANTLR 隐式乘法 的相关文章

随机推荐

  • 如何在 Django 中创建装饰器来装饰视图

    我有观点 decorator def func request hello hello return render to responce test html locals 和模板 test html hello username 我想写装
  • 如何在不注册机器人帐户的情况下以编程方式从维基共享资源下载图像?

    机器人帐户获得批准的唯一方法似乎是添加或编辑维基媒体上已有的信息 如果您尝试在没有机器人帐户的情况下使用某些 api 库下载任何图像 您会收到错误消息而不是图像 似乎他们阻止了任何不从浏览器进入的人 其他人有这方面的经验吗 我在这里错过了什
  • 提交触发后 Bitbucket 构建错误

    我试图在使用 BitBucket 插件提交时自动触发构建 我似乎使用 Web Hook 正确设置了内容 并选中项目中的 将更改推送到 BitBucket 时构建 框 当我提交时 我在 BitBucket Hook Log 中看到一条消息 显
  • 继承对象的 XML 反序列化

    我有一个对象InputFile它有数组和对象来保存文件的内容 我也有ABCFile and XYZFile两者都继承自InputFile它将读取不同类型的文件并将它们存储到的投影成员中InputFile 由于这两个对象的序列化和反序列化与父
  • Flutter Web 中的分段文件上传

    有没有办法将文件分段上传到 Flutter Web 原生的服务器 因为 Flutter iOS 和 Android 有很多方法可以做到这一点 对于 Android IOS 我们使用 multiPFile await MultipartFil
  • 无法使用 AKS 和 ACR 提取新映像

    我突然在使用 AKS 从 Azure 容器注册表中提取最新映像时遇到问题 之前工作正常 If I run kubectl describe pod
  • CodeIgniter htaccess 修改为半 https 且无 www 版本

    htaccess 修改与核心 PHP 中不同 因此 经过一番搜索 我得到了以下代码 在那之前 我的要求是我的项目的标准 整个网站严禁使用 www 即直接重定向到非 www 版本 HTTPS 适用于某些页面 结帐 登录页面 其他页面严格采用
  • Android 自定义对话框的昏暗背景

    正如标题所示 我似乎无法调暗我制作的自定义对话框的背景 网上无数的解决方案都提到了下面第一个片段中的最后 3 行代码 这对对话框的 UI 没有影响 请看下面的代码 Dialog dialog new Dialog MainActivity
  • iOS SDK中逐行读取文件

    我有一个文本文件如下 line1 line2 line3 line4 line5 我想从文件读入两个字符串数组 以便line1 line3 line 5 进入array1 and line 2 line 4 line 6 进入array2
  • 将 ISO 8601 日期时间字符串反序列化为 C# DateTime

    我正在尝试使用 JsonConvert DeserializeObject
  • 按钮动画像ios游戏中心按钮

    我正在尝试让我的按钮像 ios 游戏中心中的按钮一样具有动画效果 它们似乎像气泡一样在屏幕上摇摆和漂浮 我尝试过在屏幕上随机移动按钮 使它们同时以恒定的圆形路径移动 但效果不一样 我需要一种摇摆效果 任何想法表示赞赏 结合几个CAKeyfr
  • Scenebuilder 2.0 中的自定义组件

    在 Scenebuilder 1 1 中 您可以将整个自定义组件作为一个整体导入 然而 在 2 0 中 它将组件作为单独的部分 容器和节点 导入 由于我的自定义组件依赖于与其控制器和 ID 的统一工作 因此这会破坏它 到目前为止我能做些什么
  • 动态编译依赖于特定类加载器加载的类的java代码

    我们有能力即时动态编译 Java 代码 我至少知道Java 运行时编译器 https github com OpenHFT Java Runtime Compiler and 内存Java编译器 https github com trung
  • WCErrorCodeDeliveryFailed:无法交付有效负载

    我正在开发一款在 iPhone 和 Apple Watch 之间共享数据的应用程序 使用WCSession方法sendMessage replyHandler errorHandler 实施该方法后 我收到如下错误 WCSession on
  • GitHub SSH 密钥声称未使用

    为什么 在我的 GitHub 帐户上的 设置 gt SSH 密钥 下 它显示 由 GitHub for Mac 于 2014 年 10 月 24 日添加 从未使用过 没用过 我用过 我的个人资料中显示了很多贡献 从that机器 我还有另一把
  • Android:使用 onTouchListener() 循环执行线程

    您好 我的应用程序中有 8 个按钮 每个按钮都配置为 onclickListener 当单击该按钮时 字符串将写入套接字 现在我希望当我按住按钮时 字符串必须循环写入 这就是我正在尝试做的事情 bLeft setOnTouchListene
  • 在 Ubuntu 上安装 Java 7

    Note 这个问题是在 Oracle 将 OpenJDK 作为 Oracle JDK 的免费版本之前提出的 历史答案反映了这一点 从 2022 年起 您不应使用 Java 7 除非您必须使用无法在 OpenJDK 8 上运行的项目 为了安装
  • ELK 未将元数据从 filebeat 传递到 Logstash

    通过以下方式安装 ELK 服务器 https www digitalocean com community tutorials how to install elasticsearch logstash and kibana elk sta
  • R 编程:从数据框中查找所有因子

    我正在尝试获取数据框列的类类型 我正在做的是 sapply mydata class 但现在 我只想找到那些作为因素的列名 我尝试了以下方法 sapply data is factor 但它给了我 ResponseFlag Gender M
  • ANTLR 隐式乘法

    我是 ANTLR 的新手 我正在尝试扩展所提供的简单计算器的示例here https stackoverflow com a 1932664 具体来说 我尝试添加一些简单的函数 负数等 以熟悉 ANTLR 然而 我在尝试实现 隐式 乘法时遇