主要内容,容后补续。
先贴出C语言代码
#include <stdio.h> #include <stdlib.h> //定义状态 #define ST_NIL 0 //初始状态 #define ST_NUM 1 //操作数状态 #define ST_OP 2 //操作符状态 #define ST_END 3 //结束状态 int calc(int n1,int n2,char sign) { switch (sign) { case '+': return n1+n2; case '-': return n1-n2; case '*': return n1*n2; case '/': return n1/n2; default: return 0; } } int num_arr[2]; //操作数数组 int op_arr[2]; //运算符数组 int num_count; //操作数个数 int op_count; //运算符个数 // mode==0,遇到运算符,计算部分表达是 // mode==1,遇到表达是结束符,计算整个表达式 // 使用全局变量num_arr,和op_arr void do_calc(int mode) { switch ( op_count) { case 0: break; //不需要计算 case 1: //此时,应该有2个操作数,1个操作, 表达式可能是"1+2"这样的形式 if (mode==1) { num_arr[0]=calc(num_arr[0],num_arr[1],op_arr[0]); num_count=1; op_count=0; } break; case 2: //此时,应该有2个操作数,2个操作符号, 表达式可能是"1+2*"这样的形式 num_arr[0]=calc(num_arr[0],num_arr[1],op_arr[0]); op_arr[0]=op_arr[1]; num_count--; op_count--; break; default: printf("Error!!!\n"); //应该不会到这儿 break; } } int calc_expression(char *szString) { int curr_num; //正在输入的数,当遇到运算符或字符串结束,将curr_num复制到num_arr int pre_status, //上次状态 curr_status, //当前状态 st_comb; //上次状态和当前状态的组合 char *p=szString; pre_status=ST_NIL; num_count=0; //已经得到的操作数的个数 op_count=0; //已经得到的运算符的个数 curr_num=0; while (1) { char ch=*p++; if (ch>= '0' && ch<='9') curr_status=ST_NUM; else if ( ch == '+' || ch=='-' || ch=='*' || ch=='/') curr_status=ST_OP; else curr_status=ST_END; //前次状态有4种可能的取值,当前状态也有4种可能的取值,他们的组合有16种,其中只有5种状态是有效的 st_comb= pre_status * 4 + curr_status; switch ( st_comb) { case ST_NIL*4+ST_NUM: //上次状态是ST_NIL,当前状态是ST_NUM case ST_OP*4+ST_NUM: //上次状态是ST_OP,当前状态是ST_NUM case ST_NUM*4+ST_NUM: //上次状态是ST_NUM,当前状态是ST_NUM curr_num=curr_num*10+ch-'0'; break; case ST_NUM*4+ST_OP: //上次状态是ST_NUM,当前状态是ST_OP num_arr[num_count++]=curr_num; //操作数存入数组 curr_num=0; //为下一次输入做准备 op_arr[op_count++]=ch; //操作符存入数组 do_calc(0); break; case ST_NUM*4+ST_END: //上次状态是ST_NUM,当前状态是ST_END num_arr[num_count++]=curr_num; // curr_num=0; //为下一次输入做准备 do_calc(1); return num_arr[0]; default: printf("The %dth char is invalid\n",p-szString); return 0; } pre_status=curr_status; } } int main() { //char *string="1234+5678-1111*9876/4321"; char buff[256]; printf("Please input an expression:"); gets(buff); int r=calc_expression(buff); printf("%s=%d\n",buff,r); return 0; }
再贴出汇编语言代码
; 一个简单的表达式计算器汇编程序,使用masm32语法编程,生成windows下运行的32位控制台程序 ; 功能和限制 ; 仅仅支持输入10进制整数和四则运算符,不支持输入负数 ; 使用整数运算,运算过程的中间结果和最终结果可为负数 ; 从左向右顺序计算,不支持运算符优先级 ; 计算过程中的中间结果和最终结果不超过32位带符号整数的范围 ; 例如,输入"1234+5678-1111*9876/4321",输出"13258" ; 如何编译链接该程序 ; 本程序需使用masm32来编译,若你的masm32安装在c盘,请设置如下环境变量 ; set include=c:\masm32\include ; set lib=c:\masm32\lib ; set PATH=c:\masm32\bin;%PATH% ; 若本程序名为test.asm,则运行如下命令编译和链接和运行 ; ml /c /coff calc.asm ; link /subsystem:console test.calc ; calc.exe .386 .model flat,stdcall ; 32 bit memory model option casemap :none ; case sensitive include windows.inc include user32.inc includelib user32.lib include kernel32.inc includelib kernel32.lib .data? inBuffer db 256 dup(?) ;输入缓冲区 outBuffer db 32 dup(?) ;输出缓冲区 hOutput dd ? hInput dd ? num_arr dd 2 dup (?) ;操作数数组 op_arr dd 2 dup (?) ;运算符号数组 num_count dd ? ;操作数个数 op_count dd ? ;运算符个数 curr_num dd ? pre_status dd ? curr_status dd ? st_comb dd ? tLen dd ? ;仅用于API函数调用 .const szFmtout1 db '%d',0 szOutString db 'Please input a expression:' .code ST_NIL equ 0 ;初始状态 ST_NUM equ 1 ;操作数状态 ST_OP equ 2 ;操作符状态 ST_END equ 3 ;结束状态 ;var_N1: input parameter, the first number ;var_N2: input paramenter, the second number ;var_sign: op sign calc proc far C uses ebx ecx, var_N1,var_N2,var_sign mov eax,var_N1 mov ebx,var_N2 mov ecx,var_sign check_01: cmp cl, '+' jnz check_02 add eax,ebx jmp this_exit check_02: cmp cl, '-' jnz check_03 sub eax,ebx jmp this_exit check_03: cmp cl, '*' jnz check_04 imul ebx jmp this_exit check_04: cmp cl, '/' jnz err xor edx,edx idiv ebx jmp this_exit err: xor eax,eax this_exit: ret calc endp ;var_mode: input parameter, ; mode=1,表达式分析已经完成,0:当前遇到四则运算符号 ;return value: none ;This procedure work on global array num_arr,op_arr,num_count,op_count do_calc proc far C uses ebx ecx esi,var_mode mov esi,op_count check_0: ; op_count ==0? cmp esi,0 jz this_exit ; do nothing check_1: ; op_count ==1? cmp esi,1 jnz check_2 mov edx,var_mode ; if mode==0, do nothing or edx,edx jz this_exit mov ecx, op_arr[0] invoke calc,num_arr[0],num_arr[1*4],op_arr[0] mov num_arr[0],eax mov num_count,1 mov op_count,0 jmp this_exit check_2: ; op_count ==2 ? cmp esi,2 jnz err_input invoke calc,num_arr[0],num_arr[1*4],op_arr[0] mov num_arr[0],eax mov eax,op_arr[1*4] ; op_arr[0]=op_arr[1] mov op_arr[0],eax dec num_count ; num_count-- dec op_count ; op_count-- jmp this_exit ; op_count ==1? err_input: ; do nothing,only return this_exit: ret do_calc endp ;var_string: input parameter,the expression address ;eax: output parameter, the result calc_exp proc far C USES esi edi ebx ecx ,var_string mov esi,var_string init_vars: xor ecx,ecx xor eax,eax mov num_count,eax ;num_cont=0 mov op_count, eax ;op_count=0 mov curr_num, eax ;curr_num=0 mov pre_status,ST_NIL ;pre_status=ST_NIL loop_start: ;the loop entry check_0to9: mov cl,[esi] inc esi cmp cl,'0' jl check_add_sign cmp cl,'9' jg check_add_sign do_ch_is_dig: mov curr_status,ST_NUM jmp next_02 check_add_sign: cmp cl,'+' jz do_ch_is_op check_sub_sign: cmp cl,'-' jz do_ch_is_op check_mul_sign: cmp cl,'*' jz do_ch_is_op check_div_sign: cmp cl,'/' jz do_ch_is_op jmp do_op_is_others do_ch_is_op: mov curr_status,ST_OP jmp next_02 do_op_is_others: mov curr_status,ST_END jmp next_02 next_02: mov eax,pre_status shl eax,2 add eax,curr_status mov st_comb,eax ;st_comb=pre_status*4+curr_status check_01: cmp st_comb,ST_NIL*4+ST_NUM ;last status is ST_NUL,curr status is ST_NUM, jz case_01 check_02: cmp st_comb,ST_OP*4+ST_NUM ;last status is ST_OP,curr status is ST_NUM jz case_01 check_03: cmp st_comb,ST_NUM*4+ST_NUM ;last status is ST_NUM,curr status is ST_NUM jz case_01 check_04: cmp st_comb,ST_NUM*4+ST_OP ;last status is ST_NUM,curr status is ST_OP jz case_02 check_05: cmp st_comb,ST_NUM*4+ST_END ;last status is ST_NUM,curr status is ST_END jz case_03 jmp case_error ;invalid status, jump to case_error case_01: ;st_comb is ST_NIL*4+ST_NUM,ST_OP*4+ST_NUM or ST_NUM*4+ST_NUM mov edx,curr_num shl edx,1 ;edx =curr_num *2 lea eax,[edx+edx*4] ;eax= curr_num *10 sub cl,'0' movzx edx,cl add eax,edx mov curr_num,eax ;curr_num=curr_num + cl-'0' jmp next_loop case_02: ;st_comb is ST_NUM*4+ST_OP mov ebx,num_count mov eax,curr_num mov num_arr[ebx*4],eax ;num_arr[num_count++]=curr_num inc ebx ;num_count++ mov num_count,ebx mov curr_num,0 mov ebx,op_count movzx eax, cl ;op_arr[op_count++]= curr char mov op_arr[ebx*4],eax inc ebx ;op_count++ mov op_count,ebx invoke do_calc,0 jmp next_loop case_03: ;st_comb is ST_NUM*4+ST_END mov eax,curr_num mov ebx,num_count mov num_arr[ebx*4],eax ;num_arr[num_count++]=curr_num inc ebx ;num_count++ mov num_count,ebx ;mov curr_num,0 invoke do_calc,1 jmp this_exit ;return num_arr[0] case_error: xor eax,eax mov num_arr[0],eax jmp this_exit ;invliad case, return 0 next_loop: mov edx,curr_status ;pre_status=curr_status mov pre_status,edx jmp loop_start this_exit: mov eax,num_arr[0] ret calc_exp endp main proc far start: invoke GetStdHandle,STD_OUTPUT_HANDLE ; 获取控制台输出设备的句柄 mov hOutput,eax invoke WriteConsole,hOutput,addr szOutString,sizeof szOutString,addr tLen,0 invoke GetStdHandle,STD_INPUT_HANDLE ; 获取控制台输入设备的句柄 mov hInput, eax invoke ReadFile,hInput,addr inBuffer,sizeof inBuffer,addr tLen,NULL invoke calc_exp, addr inBuffer ;计算表达式inBuff, mov num_arr[0], eax ;将这个数存入number invoke wsprintf, addr outBuffer , addr szFmtout1,num_arr[0] invoke WriteConsole,hOutput,addr outBuffer,eax,addr tLen,0 xor eax, eax invoke ExitProcess,eax ;退出进程 ret main endp end main