学习了编译原理的scan和parsing之后写了一个简单的算数表达式解析器,输入为算数表达式,输出结果,支持括号和浮点数运算。
首先画出DFA,根据状态间的转移求出getToken函数。
然后求出EBNF:
<exp> -> <term> { <addop> <term> }
<addop> -> + | -
<term> -> <factor> { <mulop> <factor> }
<mulop> -> *
<factor> -> ( <exp> ) | number
并实现exp、term、factor函数。
源代码:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#define BUFLEN 1024
#define MAXTOKENLEN 256
// token的类型
typedef enum

...{
// 文件结尾
ENDFILE,
// 表达式错误
ERROR,
// + - * / ( )符号之一
SYMBOL,
// 数字
NUM,
} TokenType;
// DFA中的状态
typedef enum

...{
START, // 开始状态
INUM, // 数字的中间状态
DOT, // 接受到符号.的状态
END // 结束状态
} StateType;
int bufIndex;
char buffer[BUFLEN]; // 缓冲区
char tokenString[MAXTOKENLEN+1]; // 当前token
double exp();
double term();
double factor();
// 获取缓冲区下一个字符
char getNextChar()

...{
int len = strlen(buffer);
if(bufIndex < len)
return buffer[bufIndex++];
else
return EOF;
}
// 缓冲区回退一个字符
void ungetNextChar()

...{bufIndex--;}

// 获取缓冲区下一个token,并返回token的类型
TokenType getToken()

...{
int tokenIndex = 0;
TokenType currentType;
StateType state = START;
bool save;
while(state != END)

...{
char c = getNextChar();
save = true;
switch(state)

...{
case START:

...{
if(isdigit(c))
state = INUM;
else if(c == '+' || c == '-' || c == '*' || c == '/' ||
c == '(' || c == ')')

...{
currentType = SYMBOL;
state = END;
}
else if(c == EOF)

...{
currentType = ENDFILE;
state = END;
}
else

...{
currentType = ERROR;
state = END;
}
break;
}
case INUM:

...{
if(c == '.')
state = DOT;
else if(c == EOF)

...{
currentType = NUM;
state = END;
}
else if(!isdigit(c))

...{
ungetNextChar();
save = false;
currentType = NUM;
state = END;
}
break;
}
case DOT:

...{
if(isdigit(c))
state = INUM;
else

...{
currentType = ERROR;
state = END;
}
break;
}
}
if(save && tokenIndex < MAXTOKENLEN)
tokenString[tokenIndex++] = c;
if(state == END)
tokenString[tokenIndex] = '/0';
}
return currentType;
}
// 输出错误信息
void error()

...{
printf("syntax error! ");
exit(1);
}

// parsing中的match函数
void match(const char* expectedToken)

...{
if(strcmp(expectedToken, tokenString) == 0)
getToken();
else
error();
}
double exp()

...{
double tmp = term();
while(tokenString[0] == '+' || tokenString[0] == '-')

...{
switch(tokenString[0])

...{
case '+':

...{
match("+");
tmp += term();
break;
}
case '-':

...{
match("-");
tmp -= term();
break;
}
}
}
return tmp;
}
double term()

...{
double tmp = factor();
while(tokenString[0] == '*' || tokenString[0] == '/')

...{
switch(tokenString[0])

...{
case '*':

...{
match("*");
tmp *= factor();
break;
}
case '/':

...{
match("/");
tmp /= factor();
break;
}
}
}
return tmp;
}
double factor()

...{
double tmp;
if(tokenString[0] == '(')

...{
match("(");
tmp = exp();
match(")");
}
else if(isdigit(tokenString[0]))

...{
tmp = atof(tokenString);
getToken();
}
else
error();
return tmp;
}
int main()

...{
while(scanf("%s", buffer) != EOF)

...{
bufIndex = 0;
getToken();
printf("%s = ", buffer);
printf("%lf ", exp());
}
return 0;
}
首先画出DFA,根据状态间的转移求出getToken函数。
然后求出EBNF:
<exp> -> <term> { <addop> <term> }
<addop> -> + | -
<term> -> <factor> { <mulop> <factor> }
<mulop> -> *
<factor> -> ( <exp> ) | number
并实现exp、term、factor函数。
源代码:

















































































































































































































































运行结果
输入:0.265/(58-6.36*1.25)+3.16-((2.356/69.01)-3.6))
输出:0.265/(58-6.36*1.25)+3.16-((2.356/69.01)-3.6)) = 6.731155