表达式翻译器的编写

概述

        构造一个从中缀表达式到后缀形式的表达式翻译器,初步了解递归下降语法分析原理及语法制导翻译的过程。

要求

  • 表达式文法及其翻译模式定义如下:
expr -> expr + term	 {
   print(+)}
| expr - term 	{
   print(-)}
| term

term -> term * factor 	{
   print(*)}
| term / factor 	{
   print(/)}
| factor

factor -> ( expr )
| id 		{
   print(id.lexeme)}
| num 		{
   print(num.value)}
  • num为无符号整数。
  • 在后缀形式输出时,为了能区分每个单词,单词之间用空格间隔,例如,

输入: a+18*b
输出: a 18 b * +

  • 改写文法,消除该文法的左递归,然后使用语法制导翻译方案方法实现表达式的翻译。
  • 考虑简单的报错。如非法变量名、非法常量、非法字符、缺少操作数、括号不匹配等。

消除左递归

        改写文法如下:

expr -> term restterm

term ->	factor restfactor

restterm -> + term {
   print(+)} restterm
| - term {
   print(-)} restterm
| ε

restfactor -> * factor {
   print(*)} restfactor
| / factor {
   print(/)} restfactor
| ε

factor -> ( expr )
| id 	{
   print(id.lexeme)}
| num 	{
   print(num.value)}

实现方法

1.词法分析

        词法分析部分主要是区分数字常量和字符串变量,其中在此规定字符串变量由大小写字母和数字组成。为判断读取的字符是否是数字或字母,可以利用库中自带的函数isdigit和isalpha判断。

        每次读取一个词法单元都是边读取边判断,直至判断到另一类词法单元,再将读取的最后一个字符放回缓冲区,最后返回其词法单元的对应类。同时,对于运算符,就将其单独作为一类词法单元,直接返回其ASCII码值。

2.语法分析

        根据上面消除左递归的改编文法,可以构造以下子函数:

void Expr()  
{
     
   	Term();  
    Restterm();  
}  
void Term()  
{
     
	 Factor();  
	 Restfactor();  
}  
void Restterm()  
{
     
	    switch (LookAhead) {
     
	    case '+':  
	        Match('+'); Term(); printf("+ "); Restterm(); // rest --> + term {print('+')} rest  
	        break;  
	    case '-':  
	        Match('-'); Term(); printf("- "); Restterm();  
	        break;  
	    default:   // rest --> 空  
	        break;  
	    }  
}  
void Restfactor()  
{
     
	   // 与restterm类似,此处省略
} 
void Factor()  
{
     
    if (LookAhead == '(')  
    {
     
        Match('(');  
        Expr();  
        Match(')');  
    }  
    else if (LookAhead == TKN_NUM) {
     
        printf("%d ", tokenval
  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 我可以回答这个问题。中缀表达式到后缀表达式翻译器可以通过使用栈来实现。具体步骤是,从左到右扫描中缀表达式,如果遇到数字,则直接输出到后缀表达式中;如果遇到运算符,则将其与栈顶运算符进行比较,如果栈顶运算符优先级高于当前运算符,则将栈顶运算符弹出并输出到后缀表达式中,直到栈顶运算符优先级低于或等于当前运算符,然后将当前运算符入栈;如果遇到左括号,则直接入栈;如果遇到右括号,则将栈中的运算符依次弹出并输出到后缀表达式中,直到遇到左括号为止,然后将左括号弹出。最后,如果中缀表达式扫描完毕,则将栈中的运算符依次弹出并输出到后缀表达式中。 ### 回答2: 中缀表达式是我们常见的数学表达式格式,运算符位于操作数的中间,例如:2 + 3 * 4。而后缀表达式也被称为逆波兰表达式,运算符位于操作数的后面,上述例子的后缀表达式为2 3 4 * +。 编写一个中缀表达式到后缀表达式翻译器,可以通过以下步骤实现: 1. 创建一个空栈,用于存储运算符; 2. 从左到右遍历中缀表达式的每个元素; 3. 如果遇到操作数(数字),直接输出到后缀表达式; 4. 如果遇到运算符,判断栈是否为空。若为空,直接将该运算符入栈;若不为空,则比较栈顶运算符的优先级与当前运算符的优先级: - 若当前运算符的优先级高于栈顶运算符的优先级,直接入栈; - 若当前运算符的优先级小于或等于栈顶运算符的优先级,将栈顶运算符输出到后缀表达式,再将当前运算符入栈; 5. 重复步骤3和步骤4,直到遍历完整个中缀表达式; 6. 如果还有运算符在栈中,依次输出到后缀表达式; 7. 后缀表达式即为输出结果。 例如,我们将中缀表达式"2 + 3 * 4"转换为后缀表达式的过程如下: - 遍历 '2',输出到后缀表达式; - 遍历 '+',入栈; - 遍历 '3',输出到后缀表达式; - 遍历 '*',入栈; - 遍历 '4',输出到后缀表达式; - 遍历完整个中缀表达式,输出栈中的运算符到后缀表达式。 最终得到的后缀表达式为"2 3 4 * +"。可以看到,后缀表达式中运算符的优先级得到了正确的保留,并且可以直接通过后缀表达式进行计算。 ### 回答3: 中缀表达式是我们平常常见的数学表达式,操作符位于操作数的中间,如"2 + 3"。而后缀表达式则是操作符位于操作数之后的表达式,如"2 3 +"。编写一个中缀表达式到后缀表达式翻译器主要包括以下步骤: 1. 创建一个字符栈和一个结果列表。 2. 从左到右扫描中缀表达式中的每个字符。 3. 如果遇到操作数(数字),直接将其添加到结果列表中。 4. 如果遇到操作符,首先判断字符栈是否为空。如果为空,直接将操作符入栈。如果不为空,比较操作符与栈顶操作符的优先级: a. 如果当前操作符的优先级大于栈顶操作符的优先级,直接将当前操作符入栈。 b. 如果当前操作符的优先级小于等于栈顶操作符的优先级,将栈顶操作符出栈并添加到结果列表中,然后将当前操作符入栈。 5. 如果遇到左括号"(",直接将其入栈。 6. 如果遇到右括号")",将字符栈中的操作符依次出栈并添加到结果列表中,直到遇到左括号为止。将左括号出栈且不添加到结果列表。 7. 扫描完所有字符后,将字符栈中的操作符依次出栈并添加到结果列表中。 8. 返回结果列表中的后缀表达式。 例如,对于中缀表达式"2 + 3 * 4 - (5 + 6)",通过以上步骤,可以得到后缀表达式"2 3 4 * + 5 6 + -"。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值