当前位置: 首页 > backend >正文

关于编译原理——语义翻译器的设计

学习目标:

根据属性定义编写预测翻译程序,以便对输入的符号串进行语法和语义分析,并计算各文法符号的语义值。通过编写预测翻译程序掌握属性定义的应用以及语义值的计算方法,并掌握预测翻译程序的构造方法。


一、实验内容:

对下列表达式属性定义编写预测翻译程序,要求对输入的算术表达式进行语义分析:

(1)E->T  {R.i=T.val}

         R  {E.val=R.s}

(2)R->+

         T    {R1.i=R.i+T.val}

         R1    {R.s = R1.s }

          |

          -

          T     {R1.i=R.i-T.val}

         R1     {R.s=R1.s}

           |

           ε    {R.s=R.i}

(3)T->F     {Q.i=F.val}     

         Q    {T.val=Q.s}

(4)Q->*

         F      {Q1.i=Q.i*F.val}

         Q1    {Q.s=Q1.s}

          |

          /  

         F       {Q1.i=Q.i/F.val}

         Q1     {Q.s=Q1.s}

          |

          ε       {Q.s=Q.i}

(5)F-> (E)      { F.val=E.val}

          |

         Num      {F.val = num.lexval}

二、设计方案

主要包括模块功能分区、全局变量以及函数接口三个部分

(一)模块设计:

1.1 词法分析器 (Lexer)

功能: 将输入的算术表达式分解为一系列的Token。

输入: 算术表达式字符串。

输出: Token列表。

1.2 语法分析器 (Parser)

功能: 构建表达式的抽象语法树(AST)。

输入: Token列表。

输出: 抽象语法树。

1.3 求值器 (Evaluator)

功能: 计算抽象语法树的值。

输入: 抽象语法树。

输出: 表达式的计算结果。

(二)全局变量:

1.tokens[]: 存储Token的数组。

2.tokenIndex: 当前Token的索引。

)函数接口:

1.词法分析器函数接口:

getNextToken();

输入: 无参数,依赖于全局变量 tokenIndex 和 tokens 数组。

输出: 返回一个指向 Token 结构的指针,该结构包含当前 Token 的类型和值。如果没有更多的 Token,返回 NULL。

tokenize(const char* input)

输入: 字符串 input,表示要被分解的算术表达式。

输出: 修改全局变量 tokens 数组,填充 Token 结构体数组,每个结构包含表达式中的一个元素(数字、运算符等)的类型和值。

2.语法分析器函数接口:

parseExpression()

输入: 无参数,依赖于全局 tokens 数组和 tokenIndex 索引。

输出: 无返回值,用于构建并打印表达式的抽象语法树。

3.求值器函数接口:

evaluate()

输入: 无参数,依赖于由 Parser 构建的抽象语法树结构。

输出: 返回一个 double 类型的值,表示表达式计算的结果。

三、测试方案及测试结果

测试方案①:输入10*20-30

测试方案②:输入10+(20-5)/5

四、学习小结

在本次实验中,我根据属性定义编写预测翻译程序,以便对输入的符号串进行语法和语义分析,并计算各文法符号的语义值。通过编写预测翻译程序掌握属性定义的应用以及语义值的计算方法,并掌握预测翻译程序的构造方法,体会到了如何通过符号表、语义规则等手段将源代码转化为可执行的中间表示,过程中不仅要注重语法结构的正确性,还需要保证每个变量、常量、运算符等元素在不同阶段都能准确地表达其语义。

附录:主要方法的源代码

#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>typedef enum {TOKEN_NUMBER,TOKEN_PLUS,TOKEN_MINUS,TOKEN_MUL,TOKEN_DIV,TOKEN_LPAREN,TOKEN_RPAREN,TOKEN_EOF
} TokenType;typedef struct {TokenType type;double value;char lexeme[10];
} Token;Token* tokens;
int tokenIndex = 0;
Token* getNextToken() {// 假设有一个全局变量或成员变量 tokens 存储 Token 数组// 以及一个全局变量或成员变量 tokenIndex 作为当前令牌索引if (tokenIndex < 10) { // 假设有10个 Tokenreturn &tokens[tokenIndex++]; // 返回当前 Token 并递增索引}return NULL; // 如果没有更多 Token,返回 NULL
}void tokenize(const char* input) {tokens = malloc(10 * sizeof(Token));strcpy(tokens[0].lexeme, "10"); tokens[0].type = TOKEN_NUMBER;strcpy(tokens[1].lexeme, "20"); tokens[1].type = TOKEN_NUMBER;strcpy(tokens[2].lexeme, "*"); tokens[2].type = TOKEN_MUL;strcpy(tokens[3].lexeme, "30"); tokens[3].type = TOKEN_NUMBER;strcpy(tokens[4].lexeme, "-"); tokens[4].type = TOKEN_MINUS;strcpy(tokens[5].lexeme, "("); tokens[5].type = TOKEN_LPAREN;strcpy(tokens[6].lexeme, "20"); tokens[6].type = TOKEN_NUMBER;strcpy(tokens[7].lexeme, "-"); tokens[7].type = TOKEN_MINUS;strcpy(tokens[8].lexeme, "5"); tokens[8].type = TOKEN_NUMBER;strcpy(tokens[9].lexeme, ")"); tokens[9].type = TOKEN_RPAREN;tokenIndex = 10;
}void parseExpression() {Token* t = getNextToken();while (t != NULL) {switch (t->type) {case TOKEN_NUMBER:printf("Number: %s\n", t->value);break;case TOKEN_PLUS:printf("Plus\n");break;case TOKEN_MUL:printf("Multiply\n");break;// Add more cases for other tokens}t = getNextToken();}
}double evaluate() {double result = 0;Token* t = getNextToken();while (t != NULL) {switch (t->type) {case TOKEN_NUMBER:result = t->value;break;case TOKEN_PLUS:result += getNextToken()->value;break;case TOKEN_MUL:result *= getNextToken()->value;break;// Add more cases for other tokens}t = getNextToken();}return result;
}int main() {const char* expression = a;printf("请输入一个算术表达式:");tokenize(expression);parseExpression();printf("计算结果为:%f!\n", evaluate());return 0;
}

http://www.xdnf.cn/news/1511.html

相关文章:

  • 异构迁移学习(无创脑机接口中的跨脑电帽迁移学习)
  • 开发体育直播系统后台权限设计实践分享|ThinkPHP 技术栈落地案例
  • -PHP 反序列化POP 链构造魔术方法流程漏洞触发条件属性修改
  • 开源版「v0」OpenUI:根据文本生成UI界面代码
  • Sqlserver 自增长id 置零或者设置固定值
  • 【工具变量】各市ZF数字治理指标数据集(2001-2024年)
  • RabbitMQ 详解(核心概念)
  • 什么是回表?
  • A2A协议实现概览:多语言生态系统的蓬勃发展
  • vue项目中使用tinymce富文本编辑器
  • 楼宇自控系统如何打破传统桎梏,为建筑管理开创全新思路
  • 京东商品详情数据 API 接口讨论学习
  • Python内置函数---bytearray()
  • 八大排序算法
  • git pull的时候报错
  • 主流开源 LLM 应用开发平台详解
  • 记录下递归
  • 0.(新专栏目录)数据分类的艺术:从理论到实践的全面指南
  • 结构型模式:适配器模式
  • java后端开发day35--集合进阶(四)--双列集合:MapHashMapTreeMap
  • leetcode 二分查找应用
  • Linux/AndroidOS中进程间的通信线程间的同步 - IPC方式简介
  • Podman Desktop:现代轻量容器管理利器(Podman与Docker)
  • 基于stm32的智能门锁系统
  • ecovadis评估注意事项?ecovadis评估过程需要多长时间
  • gem5-gpu教程05 内存建模
  • 46. 全排列
  • Prisma JSON存储扩展性
  • 1.6软考系统架构设计师:架构师的角色与能力要求 - 练习题附答案及超详细解析
  • OpenCV图像轮廓示例