ysyx:对数学表达式分析的理解

  要解析一个带有括号的长表达式并没有想象中那么容易。 

  首先,数学表达式的递归分解顺序和日常的顺序是完全相反的。在标准的数学四则表达式里,我们的计算顺序是从左往右,从高到低,优先计算括号内容。 由于我们使用的是递归的思路,代码拆分表达式的过程和计算顺序是完全相反的:  一方面,原本的高优先级级运算符要后进行拆分,先拆低优先级运算符。另一方面,原本的从左到右的运算顺序使得拆分运算符时要从最右侧进行拆分。

 

  我一开始对括号处理的理解有问题,识别括号时,不是两侧有括号+括号匹配就代表正确,这种理解导致的括号匹配函数写了很多没必要的内容。

按照讲义提供的逻辑,最外层括号要能包住完整式子,这才是有效的外层括号.

比如这样的一个表达式:((839*(928/((((972)))))-505)-((((666)))-(746*796/723*408-((713))))+365)

第一步肯定是去掉外层括号,然后按照+把前半部分和365切开。但是,下一步就有问题了:

(839*(928/((((972)))))-505) - ((((666)))-(746*796/723*408-((713)))) 这一部分,看起来两侧有括号,而且括号左右匹配,那应该继续返回true,去掉最外层再继续吗?实际上不行,因为最外层的括号并不是包裹整个式子的。

如果去掉多余括号,变成(839*(928/972)-505) - (666-(746*796/723*408-713))。可以看到这个式子其实已经没有最外层括号了,所以应该返回的是false,按照中间的减号拆分。要做到这一点,可以考虑加减左右括号,如果还没到末尾左右括号就对应消耗完了,说明最外层括号已经没了。如果括号不匹配,那直接报错暂停就行了,没没必要再传false给eval函数。

 

  一生一芯的讲义其实已经提供了良好的思路,按照讲义的思路走就可以了。唯一需要单独处理的就是解地址符号,因为这个是单目运算符。我在考虑之后,增加了一个函数,作用是在扫描出指针和地址token以后,去掉指针token,因为已经没必要留着了,留着反而会影响表达式的递归分割,数值直接存在地址token的附加部分就行。此外,如果有负数,也可以考虑用类似的思路去单独处理。自增和自减比较麻烦,可能需要进一步增加token类型。

 ----------------------------------------------------

  第二个遇到的问题是:代码里全程都使用的是uint32,但这样存在一个问题,就是在计算除法时,假如被除数和除数里有一个是负数(按人的理解),在uint里会被强制转换为正数,导致计算出问题,所以如果想全程保持uint,那么除法这里就需要把两个数先强转int型再计算。

举例:(((261))-826*(739)*(480-((789+863)))/(542)/((991)))   在计算到-715405208 /542  这一步时就出现了问题。正确结果是-1319935,但是计算成了6604358。原本的被除数被理解成了一个超大的uint,导致计算结果是一个正数(int环境)。这显然有问题。为了保险起见,我又测试了一下乘法,似乎不存在这个问题。在DIV的case里强转int后,问题解决了。

  那么问题来了,一定要全程使用uint32吗?此外,负数可以用类似的方法处理吗?我感觉uint和int在机器中的处理这一块可能还需要再多看看。
 
  除此之外,我还发现了之前写代码的一个错误思路:  对于一个有bool* 参数的函数,比如 func(bool *success),在外层函数调用func时,正确做法是bool success=false; 调用func时传入&success。 但我却一直在外层声明bool *success=false; 然后调用func(success); 这个点纠结了我一段时间。在外层直接定义*success=false,false会被理解为0.success又是一个指针,这就会导致我实际上声明了一个指向0x00000000的指针,这明显是错的。
 
 
------------------------------------------
  关于第二个问题,在答辩时和助教仔细沟通。严格来说,cpu本身是不对 有符号、无符号数 做区分的,所以全程使用的是uint32_t,但是在调试器内部,可以在方便的位置使用有符号数。比如这次遇到的除法问题。此外,宏定义里已经定义过了word_t,eval等函数也用了word_t,其他需要使用word_t的位置也应该使用word_t,这样一来,以后需要修改字长时,也只需要修改一处。
posted @ 2024-06-03 17:39  namezhyp  阅读(49)  评论(0编辑  收藏  举报