递归下降来求解中缀或者后缀或者前缀表达式

 

学习数据结构的时候学到栈的时候都会学习使用栈来实现求解中缀表达式,思路就是扫描一遍,数字输出,符号根据优先级决定入栈和出栈的时间,然后生成后缀表达式,对后缀表达式的求解是容易的,直接扫描一遍,遇到数字入栈,遇到操作符就直接取栈顶的两个元素做运算。

好久之前实现上面所说的程序是第一个感受“编译”的感觉,感觉很爽,因此一直想学一下真正的编译原理,龙书比较深奥,一直未得其奥义。这两天阅读了vczh大大的系列文章 《手写语法分析器》、《正则表达式引擎》等文章,颇有感触,遂有此文。

表达式比定义语言要容易的多,因为它可以把词法分析和语法分析很容易的结合起来,因为表达式中除了数字其它的符号均是单字符,直接判断就可以知道token类型,比较简单。

递归下降的核心在于写出无左递归的语法,写出来之后就直接写个程序去解释这个正则表达式就可以容易的搞定。源码点击这里

 

下面简单介绍一下前缀或者后缀表达式的递归下降分析:

对于前缀,scheme中的表达式都采取这样的形式,这样的形式就无需词法分析了,没有优先级的歧义。

语法定义如下:

 expr="(" op number number ")" | "(" expr ")" |number
        number= [0-9]*
        op=‘+‘ | ‘-‘ | ‘* | ‘/‘
我们之间对每个部分进行翻译即可;
比如对于number
getnumber函数应该这么写:
expr GetNumber(char* &stream) 

{ 

   expr number; //存储结果,为一个expr类对象 

   char* lookup = stream; 

   while ((*lookup) == ‘ ‘) lookup++; 

   bool flag = false; 

  while (true) 

 { 

    if ((*lookup )<= ‘9‘ && (*lookup) >= ‘0‘) 

   { 

       number.result = number.result * 10 + (*lookup) - ‘0‘; 

       ++lookup; 

       flag = true; 

   } 

   else 

      break; 

 } 

if (flag) //获得当前开头的数字,并将当前指针所指调整到数字后面一位 

  stream = lookup; 

else //当前开头开始的不是数字,当前指针不变 

{ 

  number.error = "there need a number!\n"; 

  number.error_position = lookup; 

} 

return number; 

}

有了getnumber之后getexpression就很容易了,核心部分如下:

expr expression;
    char *lookup = stream;
    expression = GetNumber(lookup);

    if (expression.error)
    {
        if (Is(lookup, "("))
        {
            expression.error = 0;

            char op = 0;
            if (op=IsOperator(lookup))
            {
                expr left_expr = Getexpression(lookup);
                if (left_expr.error)
                    return left_expr;

                char *copy_lookup = lookup;

                expr right_expr = Getexpression(lookup);
                if (right_expr.error )
                    return right_expr;

                switch (op)
                {
                    case ‘+‘:
                        expression.result = left_expr.result + right_expr.result; break;
                    case ‘-‘:
                        expression.result = left_expr.result - right_expr.result; break;
                    case ‘*‘:
                        expression.result = left_expr.result * right_expr.result; break;
                    case ‘/‘:
                    {
                        if (right_expr.result == 0)
                        {
                            expression.error = "the number divided can not be zero!\n";
                            expression.error_position = copy_lookup; break;
                        }
                        else
                        {
                            expression.result = left_expr.result / right_expr.result; break;
                        }
                    }
                    default:
                    {
                        expression.error = "the wrong operator!\n";
                        expression.error_position = lookup;
                        return expression;
                    }

                }

            }
            else
            {
                expression= Getexpression(lookup);
                if (expression.error != 0) return expression;
            }

            if (!Is(lookup, ")"))
            {
                expression.error = "there need right bracket!\n";
                expression.error_position = lookup;
            }
        }
    }
    if(expression.error==0)                     //成功获得了数字,因此将stream指针置于数字后面
    {
        stream = lookup;
    }
    return expression;

中缀的代码就得自己写啦,我也是参考vczh大大的前缀代码写了一份前缀之后,自己写了一份中缀,我们很容易从中得到启示,找到递归下降的核心所在,据此可以写出中缀表达式的求解(中缀的求解代码完全是我自己写的,错误处理部分可能存在一些漏洞),相信根据上文自己写一个中缀一定有很多收获。

时间: 2024-11-12 20:19:41

递归下降来求解中缀或者后缀或者前缀表达式的相关文章

【龙书笔记】用Python实现一个简单数学表达式从中缀到后缀语法的翻译器(采用递归下降分析法)

上篇笔记介绍了语法分析相关的一些基础概念,本篇笔记根据龙书第2.5节的内容实现一个针对简单表达式的后缀式语法翻译器Demo. 备注:原书中的demo是java实例,我给出的将是逻辑一致的Python版本的实现. 在简单后缀翻译器代码实现之前,还需要介绍几个基本概念. 1. 自顶向下分析法(top-down parsing) 顾名思义,top-down分析法的思路是推导产生式时,以产生式开始符号作为root节点,从上至下依次构建其子节点,最终构造出语法分析树.在具体实现时,它会把输入字符串从左到右

算术表达式的前缀,中缀,后缀相互转换

原博客地址:https://blog.csdn.net/smartab/article/details/81215940 中缀表达式(中缀记法) 中缀表达式是一种通用的算术或逻辑公式表示方法,操作符以中缀形式处于操作数的中间.中缀表达式是人们常用的算术表示方法. 虽然人的大脑很容易理解与分析中缀表达式,但对计算机来说中缀表达式却是很复杂的,因此计算表达式的值时,通常需要先将中缀表达式转换为前缀或后缀表达式,然后再进行求值.对计算机来说,计算前缀或后缀表达式的值非常简单. 前缀表达式(前缀记法.波

表达树—轻松获取前缀、中缀、后缀表达式(二)

一.回顾二叉树的递归遍历 前序遍历:访问根结点-->前序遍历根结点的左子树-->前序遍历根结点的右子树. 中序遍历:中序遍历根结点的左子树-->访问根结点-->中序遍历根结点的右子树. 后序遍历:后序遍历根结点的左子树-->后序遍历根结点的右子树-->访问根结点. 二.二叉树递归遍历获得表达式 假设,已知中缀表达式为:(A+B*C)/D,需要获得前缀表达式,后缀表达式. 总结:表达树的前序遍历为前缀表达式,中序遍历为中缀表达式,后续遍历为后缀表达式. 前缀表达式(前序遍

前缀、中缀、后缀表达式以及简单计算器的实现

前缀表达式(波兰表达式).中缀表达式.后缀表达式(逆波兰表达式) 介绍 三种表达式都是四则运算的表达方式,用以四则运算表达式求值,即数学表达式的求解. 前缀表达式 前缀表达式是一种没有括号的算术表达式,与中缀表达式不同的是,其将运算符写在前面,操作数写在后面.为纪念其发明者波兰数学家Jan Lukasiewicz,前缀表达式也称为“波兰式”.例如,- 1 + 2 3,它等价于1-(2+3). 中缀表达式 中缀表达式就是一般的算数表达式,操作符以中缀形式出现在操作数之间. 后缀表达式 后缀表达式指

Atitit 表达式原理 语法分析&#160;原理与实践 解析java的dsl &#160;递归下降是现阶段主流的语法分析方法

Atitit 表达式原理 语法分析 原理与实践 解析java的dsl  递归下降是现阶段主流的语法分析方法 于是我们可以把上面的语法改写成如下形式:1 合并前缀1 语法分析有自上而下和自下而上两种分析方法2 递归下降是现阶段主流的语法分析方法,2 于是我们可以把上面的语法改写成如下形式: 1)       Operator="+" | "-" | "*" | "/" 2)       Expression=<数字>

递归下降分析程序

一.      实验目的 编制一个递归下降分析程序 LL(1)文法: E->TE1 E1->+TE1|-TE1|∑ T->FT1; T1->*FT1|/FT1|∑ F->(E)|i|1 二.      实验内容和要求 输入:LL(1)文法 判断:每遇到一个终结符,则判断当前读入的单词符号是否与该终结符相匹配,若匹配,则继续读取下一个单词符号,若不匹配,则进行错误处理. 每遇到一个非终结符,则调用相应的分析子程序 一.      实验方法.步骤及结果测试   1.   源程序名

实验三、 递归下降分析程序实验

一.        实验目的     练习构造递归下降语法分析程序的方法,熟悉上下文无关文法的使用,加深对课堂教学的理解:提高语法分析方法的实践能力 二.        实验内容和要求 对于给定的文法G[E]               E->TE'              E'->+TE' | ε             T->FT'             T'->*F T'| ε             F->(E) | i 采用递归下降语法分析法编写语法分析程序,该

用递归下降分析求表达式的值

<数据结构>中表达式求值的经典算法是用两个栈,一个存数字,一个存运算符.依次读入表达式中的每个字符,若是数字则进数字栈,若是运算符则和运算符栈的栈顶运算符比较优先权作相应操作,直至整个表达式求值完毕.运算符的优先级表如下   + - * / ( ) # + > > < < < > > - > > < < < > > * > > > > < > > / > >

【信息学奥赛一本通】第三部分_栈 ex1_4cale (中缀转后缀7符号)

其实这个中缀转后缀是费了很大功夫的,明白算法后第一次实现花了近三小时ORZ #include <stdio.h> #include <string.h> #include <ctype.h> char Mstr[511],Msta[511] = {'@'},Bstr[511]; int sta[511]; const short list[4][4] = {{0,-1,1,1},{1,0,1,1},{1,1,1,-2},{-1,-1,2,1}}; int level (