PA1实验总结

  • 基础设施
  • PA1.1基础设施
    • 单步执行
    • 打印寄存器
  • PA1.2 表达式求值
    • 1. 词法分析(识别token)
    • 2. 递归求值
  • PA1.3实现监视点

基础设施

在实现基础实施前需要的是进行源码的阅读,并且实现寄存器的模拟。实验中已经给了提示,如果需要实现寄存器的模拟需要掌握什么是匿名。只有在了解了什么是union后才可以实现寄存器的模拟,下附实现的代码(代码永远不唯一)。

 typedef struct {union{union{   uint32_t _32;                                                                             uint16_t _16;uint8_t _8[2];} gpr[8];/* Do NOT change the order of the GPRs' definitions. *//* In NEMU, rtlreg_t is exactly uint32_t. This makes RTL instructions1. in PA2 able to directly access these registers.*/   struct{uint32_t eax;uint32_t ecx;uint32_t edx;uint32_t ebx;uint32_t esp;uint32_t ebp;uint32_t esi;uint32_t edi;};  };  vaddr_t eip;} CPU_state;

在实现了寄存器模拟后,开始进行基础设施的搭建。

PA1.1基础设施

单步执行

实现单步执行的功能有两个关键点:

  1. 学习strtok()函数。直接去查找库函数的官方文档即可。
  2. 调用cpu_exec()函数。
static int cmd_si(char *args){   char *arg = strtok(args," ");// printf("%s\n",arg);if(arg == NULL){printf("too few arguments.\n");return 1;}int num = atoi(arg);cpu_exec(num);printf("OK");return 0;
};


注:附上的代码注释部分是用来测试用的。

打印寄存器

打印寄存器部分比较容易实现,只需要用strtok()函数将字符串分割成想要的部分即可。

static int cmd_info(char *args){char *arg = strtok(args," ");printf("%s\n",arg);//cpu infoif (strcmp(arg,"r")==0){printf("eax is %x\n",cpu.eax);printf("ecx is %x\n",cpu.ecx);printf("edx is %x\n",cpu.edx);printf("ebx is %x\n",cpu.ebx);printf("esp is %x\n",cpu.esp);printf("ebp is %x\n",cpu.ebp); printf("esi is %x\n",cpu.esi);printf("edi is %x\n",cpu.edi);printf("---------------------------\n");}else if(strcmp(arg,"w")==0){print_wp();    //此部分是后期用来打印监测点状态使用,前期可以先注释掉。}return 0;
}

### 扫描内存
这部分直接给出代码,没有什么特别的思考逻辑。

static int cmd_x(char *args){//获取内存起始地址和扫描长度。if(args == NULL){printf("too few parameter! \n");return 1;}char *arg = strtok(args," ");if(arg == NULL){printf("too few parameter! \n");return 1;}int  n = atoi(arg);char *EXPR = strtok(NULL," ");if(EXPR == NULL){                                                                                                                                          printf("too few parameter! \n");return 1;}if(strtok(NULL," ")!=NULL){printf("too many parameter! \n");return 1;}bool success = true;//vaddr_t addr = expr(EXPR , &success);if (success!=true){printf("ERRO!!\n");return 1;}char *str;// vaddr_t addr = atoi(EXPR);vaddr_t addr =  strtol( EXPR,&str,16 );// printf("%#lX\n",ad);//进行内存扫描,每次四个字节;for(int i = 0 ; i < n ; i++){uint32_t data = vaddr_read(addr + i * 4,4);printf("0x%08x  " , addr + i * 4 );for(int j =0 ; j < 4 ; j++){printf("0x%02x " , data & 0xff);data = data >> 8 ;}printf("\n");}return 0;
}

PA1.2 表达式求值

这个部分我用了比较长的时间,而且在做后面的实验时又对这个部分进行了补充。对于这部分,我不会贴出全部源代码,只会给出实验结果和思路。
整个表达式求值的过程我分成了两个部分:

1. 词法分析(识别token)

在进行此法分析时,首先要进行的是了解正则表达式。正则表达式的用途很广,而且很神奇,最重要的是还很复杂。在此我大概说一下自己在实现这个部分是走过的坑。
第一个坑毫无疑问是正则表达式的撰写,对于这个我想说的是:多测试,尽可能想的全面。只有这样才能写出一个可以使用的正则表达式。
在完成tokens识别后需要做的是将token信息存储到tokens[]数组中,这里我使用的是strncpy()函数,因为这个函数可以更好的控制字符串复制的起始位置。
至此就已经实现一个简单的词法分析器了。

2. 递归求值

在识别并记录下全部的token信息后,可以进行求值运算了,在整个求值运算中已经有了一个完整的递归框架,这里我会详细说下其中两个功能函数

  1. 括号匹配函数
bool check_parentheses(int p ,int q){// printf("--------------\n");  int i,tag = 0;if(tokens[p].type != TK_LEFT || tokens[q].type != TK_RIGHT) return false; //首尾没有()则为false for(i = p ; i <= q ; i ++){    if(tokens[i].type == TK_LEFT) tag++;else if(tokens[i].type == TK_RIGHT) tag--;if(tag == 0 && i < q) return false ;  //(3+4)*(5+3) 返回false}                              if( tag != 0 ) return false;   return true;
}
  1. 主操作符寻找函数
int dominant_operator(int p , int q){int i ,dom = p, left_n = 0;int pr = -1 ;for(i = p ; i <= q ; i++){if(tokens[i].type == TK_LEFT){left_n += 1;i++;while(1){if(tokens[i].type == TK_LEFT) left_n += 1;else if(tokens[i].type == TK_RIGHT) left_n --;i++;if(left_n == 0)break;}  if(i > q)break;}      else if(tokens[i].type == TK_NUM10) continue;else if(pir(tokens[i].type ) > pr){pr = pir(tokens[i].type);dom = i;}      }          // printf("%d\n",left_n);return dom;
}

其中pir是优先级函数,这里我按照c语言的标准对不同操作符赋予优先级。
在完成以上函数后,就已经实现了基本的表达式求值函数,接下来是对表达式求值的扩展- -负数和指针的识别。

 for(int i = 0 ;i<nr_token;i++) {if(tokens[i].type=='*'&&(i==0||(tokens[i-1].type!=TK_NUM10&&tokens[i-1].type!=TK_LEFT&&tokens[i].type!=TK_NUM16)))tokens[i].type = TK_POINT;if(tokens[i].type=='-'&&(i==0||(tokens[i-1].type!=TK_NUM10&&tokens[i-1].type!=TK_LEFT&&tokens[i].type!=TK_NUM16)))tokens[i].type = TK_NEG;}

在进行负数和指针的识别时要注意特殊情况 多个负号和多个指针,这里我在处理时加了一下代码:

       if(tokens[op].type == TK_NEG){for( i = op ; i<nr_token ; i++){if(tokens[i].type == TK_NUM10){sscanf(tokens[i].str, "%x", &result);//printf("%d \n",result);// return -result;break;}}  for( ;i > 0 ;i --) result = -result;return result;}      else if (tokens[op].type == TK_POINT){for( i = op ; i<nr_token ; i++){if(tokens[i].type == TK_NUM10){sscanf(tokens[op+1].str, "%x", &result);// result = vaddr_read(result, 4);// return result;break;}}  for( ;i > 0 ;i -- ) vaddr_read(result, 4);return result;}

这里的逻辑是统计符号的个数,然后进行相应次数的操作。
至此完成PA1.2部分。

PA1.3实现监视点

对于实现监视点功能主要有三个部分函数(监视点所需要的结构类型,大家可以自行思考,能够实现功能即可):

  1. 添加监视点:
//需要存入表达式和结果。
WP *new_wp(char *str , int value){if(su == true){init_wp_pool();su = false;//printf("!!!!!!!!!!!!!\n");}if(free_ == NULL){printf("Erro!free is null.\n");assert(0);}WP *new = NULL;new = free_;free_ = free_->next;// printf("!!!!%d\n",value);// printf("!!!!%s\n",str);new->value = value;// printf("!!!!%d\n",new->value);strcpy(new->expr, str);// printf("!!!!%d\n",new->value);// printf("%s /n",new->expr);new->next = NULL;new->isused = true;if(head == NULL) head = new;else{new->next = head;head = new ;}return new;
}


再添加监视点前,我进行了一次判断,这个判断主要用途是判定监视点池是否完成初始化。
3. 释放监视点

void free_wp(int no){WP *p = head;if(head == NULL){                                                                                                                                          printf("监视点列表为空。 \n");assert(0);}else if(p->NO == no){head = head->next;p->value = 0;p->isused = false; p->next = free_;free_ = p;printf("已经删除第%d个监视点。\n", no);// free(p);return;}else{WP *q = head;p = p ->next;while(p!=NULL){if (p->NO == no){q->next = p->next;p->value = 0;p->isused = false;p->next = free_;free_ = p;printf("已经删除第%d个监视点。\n", no);//       free(p);free(q);return;}else{p = p -> next;q = q -> next;}}printf("不存在第%d个监视点。\n",no);return;
}
  1. 打印监视点
void print_wp(){WP *p = head;if(p ==NULL){printf("监视点为空!\n");return;}else{while(p!=NULL){printf("%d   %s 0x%08x\n",p->NO , p->expr, p->value);p=p->next;}return;}return;
}


至此已经完成了整个PA1实验,思考题每个人都会有自己的答案。

PA1--实现基础设施、表达式求值和监视点相关推荐

  1. 经典笔试上机考题-表达式求值

    相信参加过笔试面试同学应当见到过表达式求值这道题,下面列举的一道经典的考题,本文将同大家一起细细探讨一下表达式求值这一类问题的求法,希望抛砖引玉,其中有不妥的地方也请大家多多批评指正. /* 功能:四 ...

  2. NOIP2013普及组 T2 表达式求值

    OJ地址:洛谷P1981 CODEVS 3292 正常写法是用栈 1 #include<iostream> 2 #include<algorithm> 3 #include&l ...

  3. 栈 -- 顺序栈、链式栈的实现 及其应用(函数栈,表达式求值,括号匹配)

    文章目录 实现 顺序栈实现 链式栈实现 应用 函数栈 的应用 表达式求值中 的应用 括号匹配中 的应用 我们使用浏览器的时候经常会用到前进.后退功能. 依次访问完一串页面 a – b – c之后点击后 ...

  4. 【Java】LeetCode 150. 逆波兰表达式求值 (后缀表达式)

    题目: 根据 逆波兰表示法,求表达式的值. 有效的算符包括 +.-.*./ .每个运算对象可以是整数,也可以是另一个逆波兰表达式. 说明: 整数除法只保留整数部分. 给定逆波兰表达式总是有效的.换句话 ...

  5. C语言----表达式求值之隐式类型转换

    前言: 表达式求值的顺序一部分是由操作符的优先级和结合性决定. 同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型,称为隐式类型转换,下面给出隐式类型转换的详细讲解,希望对大家有所帮助~ 隐 ...

  6. [数据结构]表达式求值

    一.问题描述 表达式求值是数学中的一个基本问题,也是程序设计中的一个简单问题.我们所涉及的表达式中包含数字和符号,本实验中处理的符号包括'+'.'-'.'*'.'/'.'('和')',要求按照我们所习 ...

  7. c语言作业算术表达式求值,算术表达式求值演示(C语言版)

    //头文件预处理命令 #include #include //----------函数结果状态代码----------------- #define TRUE 1 #define FALSE 0 #d ...

  8. 严蔚敏《数据结构》C语言版 第三章 算法3.4 表达式求值

    这个我是看到华为今年招聘的机试题的第三题. 输入一串算术表达式的字符串,把它的结果算出来. 1 //表达式求值(输入.输出和中间结果均只能是0-9)运算符仅限+-*/. 2 #include < ...

  9. 函数嵌套 lisp表达式求值

    问题 D: lisp表达式求值 时间限制: 1 Sec  内存限制: 128 MB 提交: 105  解决: 43 [提交][状态][讨论版] 题目描述 lisp是一种非常古老的计算机语言,是由约翰· ...

最新文章

  1. 即时编译和提前编译_即时编译说明
  2. Linux通过XAMPP集成软件包搭建LAMPP环境
  3. ORM(一)OQL结构图
  4. mysql存储过程或函数中传入参数与表字段名相同引发的悲剧
  5. 第一行代码学习笔记第六章——详解持久化技术
  6. fiddler和wireshark工具介绍及对比 - [测试技术知识]
  7. 给数据库表字段设置默认值
  8. Golang 大杀器之跟踪剖析 trace(转载)
  9. UE4 Light Functions(光源函数)
  10. 为什么你会觉得微服务架构很别扭
  11. Hadoop启动jobhistoryserver
  12. js—封装原生AJAX
  13. Bug Algorithms
  14. SSM毕设项目国有资产管理系统3c938(java+VUE+Mybatis+Maven+Mysql)
  15. “阀值”与“阈值”的区别
  16. Silverlight XAP文件运行器
  17. 手机插了sd卡显示无服务器,手机sd卡无法读取之sd卡无文件系统或文件系统不受支持怎么办...
  18. 微信小程序 9宫格翻牌动画
  19. 纯css实现的娃娃机web前端html页面源码
  20. 黑马程序员前端实战项目---PC端品优购(下)

热门文章

  1. python对缩进太敏感...a_a
  2. java excel 分页合并_Excel办公技巧——完整显示跨页合并的单元格
  3. 2018.10.19学习总结
  4. Aardio 第一天:使用虚表和适配器+试融合Java
  5. 天池竞赛-地表建筑物识别 语义分割
  6. 八边形Octagan类(接口)
  7. node.js -- 手把手教你搭建 电商平台
  8. MODBUS通讯协议学习总结
  9. JavaScript将后端获取到的byte数组转为文件
  10. 密码破解神器海德拉GUI界面-xhydra