`
梁利锋
  • 浏览: 81894 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

用 ANTLR 做一个四则运算器

阅读更多

  开始把 D 的语法转换为 EBNF,发现 D 还支持中文变量名,也就是所谓的 UniversalAlpha,查看了一下 dmd front end 的源代码,检查字符是否 UniversalAlpha 的函数是这样的:

 

int isUniAlpha(unsigned u)
{
    static unsigned short table[][2] =
    {
 { 0x00AA, 0x00AA },
 { 0x00B5, 0x00B5 },
 { 0x00B7, 0x00B7 },
 ......
 ......
 ......
 { 0x3105, 0x312C },
 { 0x4E00, 0x9FA5 },
 { 0xAC00, 0xD7A3 },
    };
    if (u > 0xD7A3)
 goto Lisnot;

   // Binary search
    int mid;
    int low;
    int high;

  low = 0;
    high = sizeof(table) / sizeof(table[0]) - 1;
    while (low <= high)
    {
 mid = (low + high) >> 1;
 if (u < table[mid][0])
     high = mid - 1;
 else if (u > table[mid][1])
     low = mid + 1;
 else
     goto Lis;
    }

Lisnot:
    return 0;

Lis:
    return 1;
}

  

 

  但是,怎么让 Grammatica 在分析过程中调用类似的函数,却是一点儿头绪也没有。虽然,理论上来说,用正则表达式,也可以表示上面的逻辑,不过,200多行的数据,要都转成正则表达式,不止运行速度慢,就只是转换的工作量,也让人不可接受。

 

  而后,对于 D 中 string interger 和 float 的转换,再次发现 Grammatica 这种只用正则表达式的方式的严重不足,终于决定放弃 Grammatica。

 

  本来,最好的办法其实是使用 dmd 的前端的源代码来解析,不过,几乎 1.6M 的代码,没有任何文档,都读过一遍的话,黄花菜都凉了。

 

  一直不想用 ANTLR 的原因,是语法文件和嵌入的代码混编,看起来杂乱无章,但是 ANTLR 的强大和社区的活跃确实是很吸引人的。于是,决定用 ANTLR 来写 D Parser。(看到还有一个叫 coco/r 的生成器,据说比 ANTLR 清晰,不过也有语法能力不如 ANTLR 的问题,所以暂时也不考虑了。)

 

  同样的,四则运算是一个比较好的例子,从 ANTLR 的主页的“五分钟教程”中,找到一个四则运算的语法文件,看了一下,不嵌入代码的话,还挺清晰的。既然用 ANTLR,就要体验一下它自动建立抽象语法树的能力,把那个语法文件做了一些修改,成为这个样子:

 

grammar SimpleCalc;

options {
    language=CSharp;
    output=AST;
    ASTLabelType=CommonTree;
}

tokens {
    PLUS     = '+' ;
    MINUS    = '-' ;
    MULT     = '*' ;
    DIV      = '/' ;
}

@members {
}

/*------------------------------------------------------------------
 * PARSER RULES
 *------------------------------------------------------------------*/

expr    : term ( ( PLUS^ | MINUS^ )  term )* ;
term    : factor ( ( MULT^ | DIV^ ) factor )* ;
factor  : NUMBER | '(' expr ')' -> expr ;

/*------------------------------------------------------------------
 * LEXER RULES
 *------------------------------------------------------------------*/

NUMBER     : (DIGIT)+ ;
WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+     { $channel = HIDDEN; } ;
fragment DIGIT    : '0'..'9' ;

  

 

  做了修改的地方是,1.让它输出 AST,2.把运算符提取为根,3.支持括号。

 

  生成文件后,在 Program 文件中加入创建分析器的代码,再加入深度优先的语法树访问函数,以及运算部分如下:

 

using System;
using System.Collections.Generic;
using System.Text;
using Antlr.Runtime;
using Antlr.Runtime.Tree;

namespace Expr
{
    class Program
    {
        private static Stack<int> numbers = new Stack<int>();

       static void Main(string[] args)
        {
            SimpleCalcLexer lex = new SimpleCalcLexer(new ANTLRFileStream(args[0]));
            CommonTokenStream tokens = new CommonTokenStream(lex);
            SimpleCalcParser parser = new SimpleCalcParser(tokens);

           try
            {
                CommonTree ct = (CommonTree)parser.expr().Tree;
                VisitTree(ct);
                Console.WriteLine("The result is: {0}", numbers.Pop());
                Console.Read();
            }
            catch (RecognitionException e)
            {
                Console.Error.WriteLine(e.StackTrace);
            }
        }

       static void VisitTree(ITree it)
        {
            for (int i = 0; i < it.ChildCount; i++)
            {
                ITree c = it.GetChild(i);
                VisitTree(c);
            }
            switch (it.Type)
            {
                case SimpleCalcLexer.PLUS:
                case SimpleCalcLexer.MINUS:
                case SimpleCalcLexer.MULT:
                case SimpleCalcLexer.DIV:
                    Operation(it.Text, numbers.Pop(), numbers.Pop());
                    break;
                case SimpleCalcLexer.NUMBER:
                    numbers.Push(int.Parse(it.Text));
                    break;
            }
        }

    static void Operation(string opCode, int v2, int v1)
        {
            int result;
            switch (opCode)
            {
                case "+":
                    result = v1 + v2;
                    break;
                case "-":
                    result = v1 - v2;
                    break;
                case "*":
                    result = v1 * v2;
                    break;
                case "/":
                    result = v1 / v2;
                    break;
                default:
                    throw new Exception();
            }
            Console.WriteLine("{1} {0} {2} = {3}", opCode, v1, v2, result);
            numbers.Push(result);
        }
    }
}

 

 

  上面的代码,除了运算之外,还会把每一个计算步骤打印出来,在输入文件中输入“5-(3-2)+6*7”,编译运行程序,得到结果:

 

3 - 2 = 1
5 - 1 = 4
6 * 7 = 42
4 + 42 = 46
The result is: 46

 

  ANTLR 帮助建立 AST 的功能确实很舒服,而且例子也多,嗯,以后就用它了。smile

1
0
分享到:
评论
2 楼 梁利锋 2008-01-15  
也是。不过 C# 圈子好像没什么人气 
1 楼 oldrev 2008-01-15  
呵呵,老实说这4篇post其实应该发到 C# 圈子里

相关推荐

    antlr实现四则运算源码

    在本主题中,我们将深入探讨ANTLR4如何用于实现一个简单的四则运算解析器。 ANTLR4 提供了词法分析(词法器生成)、语法分析(解析器生成)和树遍历(访问语法树)等功能,这使得构建解析器变得相对简单。在这个四...

    antlr做的计算器

    在这个“ANTLR做的计算器”项目中,我们将探讨如何使用ANTLR来实现一个简单的四则运算计算器。 ANTLR工作原理的核心是通过定义语法规则(Grammar)来识别特定的语言结构。在四则运算计算器的例子中,我们需要定义...

    用ANTLR实现一个简单加法计算器

    CSDN博客上不能添加附件,将文件放在这里,以供有兴趣的下载 加法器分析的地址:http://blog.csdn.net/evenfall/archive/2010/10/31/5978379.aspx

    antlr实现的计算器

    ANTLR(ANother Tool for Language Recognition)是一个强大的解析器生成器,用于读取、处理、执行或翻译结构化文本或二进制文件。ANTLR被广泛应用于构建语言、工具和框架,尤其是那些需要解析复杂语法的系统。在这...

    c#实现四则混合运算

    为了正确处理这些运算,我们需要一个解析器来识别和处理运算符的优先级。这通常涉及到编译原理中的词法分析和语法分析过程。 词法分析(Tokenization)是将输入的字符串(表达式)分解成一个个有意义的单元,即...

    编译原理课程设计实现四则混合运算

    总结来说,"编译原理课程设计实现四则混合运算"项目提供了一个全面的实践平台,让学生们能够亲手操作编译器的各个关键步骤,从词法分析到语义分析,再到Java代码和汇编代码的生成。通过这样的实践,学习者可以深入...

    ANTLR指南(v3.0).doc

    ANTLR,全称ANother Tool for Language Recognition,是一个强大的解析器生成器,主要用于读取、处理、执行或翻译结构化文本或二进制文件。ANTLR能够根据用户提供的语言文法生成解析器,这些文法可以包含可嵌入的...

    ANTLR指南

    简而言之,ANTLR提供了一个强大的框架,用于基于用户定义的文法生成语法分析器。 #### 二、ANTLR支持的语言 ANTLR广泛支持多种现代编程语言,使得生成的语法分析器代码能够适应不同的开发环境。目前,它支持的语言...

    ParseMATLAB:使用ANTLR解析MATLAB

    ANTLR是一个强大的解析器生成器,广泛用于构建语言、工具和框架。本篇将深入探讨如何使用ANTLR来解析MATLAB语言,特别是针对Python开发者。 MATLAB是一种专为数值计算设计的高级编程语言,广泛应用于工程、科学和...

    MFPL:一种称为 MFPL 的编程语言的语法设计和实现。 用 ANTLR4 开发

    ANTLR4是一个强大的解析器生成器,常用于构建语言、工具和框架,尤其适合处理复杂的语法和解析任务。在这个项目中,MFPL的语言特性包括基本的算术和逻辑表达式,以及控制流程结构如循环。此外,它还包含类型检查功能...

    antlr_llvm_compiler

    antlr_llvm_compiler 项目包括形式语言和编译器的主题。 使用工具创建的自己语言的编译器: ... 然后根据 LLVM 规范创建一个包含实际源代码的中间表示(llvm bitcode)的文件。 您自己语言的示例源代码: 间接代表:

    编译器代码

    例如,一个加法运算可以被表示为四元式:(OP_ADD, op1, op2, res),其中op1和op2是操作数,res是结果。通过这种方式,编译器可以更容易地处理表达式的求值顺序、类型检查和其他复杂的逻辑。 总结起来,这个“编译器...

    表达式解析

    例如,ANTLR是一个流行的解析器生成器,它可以自动生成词法分析器和语法分析器的代码,大大简化了解析器的开发工作。另外,一些编程语言库如Python的`ast`模块,提供了直接构建和操作AST的功能,方便开发者进行...

    antlr4-calculator-[removed]使用ANTLR4 Javascript运行时使用语法规则对输入进行lex和解析

    使用ANTLR4 Javascript运行时来使用语法规则来解析和解析输入。 它源自。 计算器语法在Calculator.g4中。 针对Javascript(而不是默认Java)的编译语法生成.js和.token文件(包含在'js'文件夹中)。 要更改语法并...

    java编写的词法分析器

    在本例中,"wordanalysis"可能是词法分析器的输出结果文件,或者是一个实现词法分析的Java源代码文件。这个文件可能会包含一系列的记号,每个记号都由它的类别码和相应的值表示,例如: ``` (ID, "main") ...

    计算算术运算表达式

    在这个课设中,目标是编写一个程序,能够接收用户输入的算术运算表达式,并正确地计算出结果。下面我们将深入探讨这一主题,包括算术表达式的组成、解析和计算。 首先,我们需要理解算术表达式的基本概念。算术...

    matlab开发-mparser

    本文将详细介绍“matlab开发-mparser”项目,这是一个使用ANTLR编译器生成器构建的MATLAB解析器,包含了MEX接口,以支持与MATLAB的深度集成。 ANTLR是一个强大的解析器生成器,它能够读取、处理、执行或翻译结构化...

    anltr简易计算器

    这个规则定义了一个支持加减乘除四则运算的表达式结构。 ANTLR生成的Java类: ANTLR生成的Java类包括Lexer和Parser,以及它们的子类。Lexer类处理输入字符串,生成Token流;Parser类基于Token流进行解析,构建AST。...

    计算器(输入字符串解析运算)

    在IT领域,构建一个能处理复杂运算式的计算器是一项常见的任务,尤其在开发用户界面或编程语言解释器时。本文将详细探讨"计算器(输入字符串解析运算)"这一主题,包括其核心概念、实现方法和相关技术。 首先,我们...

    用XText工具开发的自定义DSL语言

    ANTLR是一个广泛使用的解析器生成器,它可以生成Java、C#、Python等多种语言的解析器和词法分析器。XText利用ANTLR生成的词法分析器将源代码分解成词法单元(如数字、运算符等),然后解析器根据定义的语法规则将...

Global site tag (gtag.js) - Google Analytics