程序是一个计算器,有4个部分组成:1.语法分析器(Parser),2.输入函数(input function),3.符号表(symbol table)4.驱动(driver).我是用的vc编译器,1,2,3用头文件,4用.cpp文件。第一部分Parser分析器,parser.h.作用是分析用户输入的语句的语法。用户可以在控制台输入以下内容:program: END expr_list ENDexpr_list: expression PRINT expression PRINT expr_listexpression: expression+term expression-term termterm: term*primary term/primary primaryprimary NUMBER NAME NAME = expression 注释:在vc中这中间好像必须有空格,不然不行,过一会再讨论这个 -primary (expression)这里说明了语法,也可以说是给用户说明了使用规则,比如:你在控制台内输入 12*3 ;,计算器就会显示36,其中不管是什么符号(这里有12,*,3,;四个)都要从primary开始进行分析(具体实现后面说),分析器分析12是NUMBER然后再取*号,向上到term,12附给了term,进行*发运算,primary又要从输入继续取值,于是取了3,算出来了36以后再向上,这时候没有+,-,就直接把36给了term,这时候分析器遇到了;号后进行输出,然后继续等待输入的值,这样循环。这是一种递归的方式。以下是Parser.h。/********************************Cal_Parser.hthe Parser of the desk calculatorrecursive descend technique*********************************/#include<map>double prim(bool); //声明double term(bool);double expr(bool);double expr(bool get){ //handle + and - operation double left=term(get); for(;;){ switch(curr_tok){ case PLUS: left+=term(true); //get a token to add break; case MINUS: left-=term(true); break; default: return left; } }}double term(bool get){ //handle * and / operation double left=prim(get); for(;;){ switch(curr_tok){ case MUL: left*=prim(true); break; case DIV: if(double d=prim(true)){ left/=d; break; } return error("devided by 0"); default: return left; } }}double prim(bool get){ //handle primaries if(get)get_token(); //get a token to decide which type and value it is switch(curr_tok){ //type which is gotten in the get_token() case NUMBER: { double v=number_value;//value gotten in get_token() get_token(); //get next return v; } case NAME: { double& v=table[string_value]; if(get_token()==ASSIGN)v=expr(true); //if the input is like "a=3" return v; } case MINUS: return -prim(true); //"-3" case LP: { double e=expr(true); if(curr_tok!=RP)return error("where is )?"); get_token(); return e; } default: return error("where is primary?"); }}程序只有3个函数,第1,第2个分别是+ -和* /,第3个是因子,都要经过prim()去取值。再来说地3个部分,符号表:我写的整个程序有4个全局变量:Token_Value curr_tok=PRINT; //hold the input type,see enum:Token_Valuedouble number_value; //hold the value the last NUMBER readstring string_value; //hold the value the last NAME readint no_of_error; //hold the number of error第一个的curr_tok是当前的输入字的类型,Token_Value是枚举型:enum Token_Value{ //input type. NAME, NUMBER, END='!', PLUS='+', MINUS='-', MUL='*', DIV='/', PRINT=';', ASSIGN='=', LP='(', RP=')' };表示的是输入字的类型,这里有11种类行,其中跟书上不一样的是END 我附了'!'的值,程序中输入!就退出。第二个是number_value,意思是如果类型是NUMBER,它就是number的值。第三个string_value,意思是如果类型是NAME,它就是name的制。比如说我输入35,number_value就等于35,curr_tok=NUMBER.又比如我输入a=90,识别a的时候,curr_tok就为NAME,string_value就为"a".第4个的no_of_error是错误的个数,用处相对来说不大。源代码,Cal_SymbolTable.h:/**********************************Cal_SymbolTable.hthe symbol table and all the global variables of desk calculator***********************************/#include <string>#include <map>using namespace std;enum Token_Value{ //input type. NAME, NUMBER, END='!', PLUS='+', MINUS='-', MUL='*', DIV='/', PRINT=';', ASSIGN='=', LP='(', RP=')' };//four global variableToken_Value curr_tok=PRINT; //hold the input type,see enum:Token_Valuedouble number_value; //hold the value the last NUMBER readstring string_value; //hold the value the last NAME readint no_of_error; //hold the number of error//mapmap<string,double>table;其中map是来存放初始化的一些固定常量如pi=3.1415926....等等,还有一个功能是存取NAME的值,比如你输入a=9 然后程序就会生成table["a"]=9,table是一个map。第2部分输入函数,get_token()这一个函数,就是取用户输入的值并且判断值得类型,是NAME?还是一个NUMBER,并且把类型给全局变量curr_tok,把number的值给number_value如果类型为NUMBER的话。原函数,Cal_Input.h:/**********************Cal_Input.hget the input from user***********************/#include<cctype>#include<iostream>using namespace std;Token_Value get_token(){ //get the value and type of value from input char ch=0; cin>>ch; switch(ch){ case 0: return curr_tok=END; case ';': //if input is operation case '*': case '/': case '+': case '-': case '(': case ')': case '=': case '!': return curr_tok=Token_Value(ch); case '0': case '1': case '2': case '3': case '4': //if number case '5': case '6': case '7': case '8': case '9': case '.': cin.putback(ch); cin>>number_value; //set value return curr_tok=NUMBER; //set type default: if(isalpha(ch)){ //'a'-'Z' cin.putback(ch); cin>>string_value; return curr_tok=NAME; } error("bad token"); return curr_tok=PRINT; }}因为输入字是以char的形式输入的,所以没有办法输入两位以上或者是小数,所以程序遇到一个数字的char的时候putback,在用cin把这个值输入完整,NAME也同样是如此第4个部分是驱动,也就是main函数。先看原文件:Cal_Driver.cpp#include "Cal_SymbolTable.h"#include "Cal_error.h"#include "Cal_Input.h"#include "Cal_Parser.h"#include <iostream>using namespace std;int main(){table["pi"]=3.1415926525897;table["e"]=2.71828182845904;while(cin){ get_token(); if(curr_tok==END)break; if(curr_tok==PRINT)continue; cout<<expr(false)<<'\n';}return no_of_error;}先预设了两个map,用table["pi"]和table["e"],都知道是什么意思吧。。。下面进行无止境的循环,除了用户输入“!”,也就是END的时候,先取数,再送到分析器分析。完

评论