继续上文扩展简易计算器,使它支持括号和负数。
修改代码如下:
在TokenKind枚举中加入左右括号的枚举值
lex.h
#ifndef _LEX_H
#define _LEX_H
typedef enum {
TOKEN_BAD,
TOKEN_NUM,
TOKEN_OP_ADD,
TOKEN_OP_SUB,
TOKEN_OP_MUL,
TOKEN_OP_DIV,
TOKEN_OP_PAREN_LEFT,
TOKEN_OP_PAREN_RIGHT,
TOKEN_LINE_END,
} TokenKind;
#define MAX_TOKEN_SIZE (100)
typedef struct {
TokenKind kind;
double value;
char str[MAX_TOKEN_SIZE];
} Token;
void SetLine(char *file);
void GetToken(Token *token);
#endif
在parser.c 中ParsePrimaryExp函数中加入解析负数和括号逻辑
parser.c
#include "parser.h"
static Token stLookAheadTok;
static int stLookAheadTokExist;
static void MyGetToken(Token *tok)
{
if (stLookAheadTokExist) {
*tok = stLookAheadTok;
stLookAheadTokExist = 0;
} else {
GetToken(tok);
}
}
static void UngetToken(Token *tok)
{
stLookAheadTok = *tok;
stLookAheadTokExist = 1;
}
static double ParsePrimaryExp()
{
Token tok;
double val = 0.0;
int minusFlag = 0;
MyGetToken(&tok);
// negative NUM
if (tok.kind == TOKEN_OP_SUB) {
minusFlag = 1;
} else {
UngetToken(&tok);
}
MyGetToken(&tok);
if (tok.kind == TOKEN_NUM) {
val = tok.value;
} else if (tok.kind == TOKEN_OP_PAREN_LEFT) { // Support ( )
val = ParseExp();
MyGetToken(&tok);
if (tok.kind != TOKEN_OP_PAREN_RIGHT) {
fprintf(stderr, "missing ')' error.\n");
exit(1);
}
} else {
// fprintf(stderr, "syntax error. \n");
// exit(1);
// return 0.0; // make compiler happy
UngetToken(&tok);
}
return minusFlag ? (-val) : val;
}
static double ParseTerm()
{
double v1;
double v2;
Token tok;
v1 = ParsePrimaryExp();
for (;;) {
MyGetToken(&tok);
if (tok.kind != TOKEN_OP_MUL
&& tok.kind != TOKEN_OP_DIV) {
UngetToken(&tok);
break;
}
v2 = ParsePrimaryExp();
if (tok.kind == TOKEN_OP_MUL) {
v1 *= v2;
} else if (tok.kind == TOKEN_OP_DIV) {
v1 /= v2;
}
}
return v1;
}
double ParseExp()
{
double v1;
double v2;
Token tok;
v1 = ParseTerm();
for (;;) {
MyGetToken(&tok);
if (tok.kind != TOKEN_OP_ADD
&& tok.kind != TOKEN_OP_SUB) {
UngetToken(&tok);
break;
}
v2 = ParseTerm();
if (tok.kind == TOKEN_OP_ADD) {
v1 += v2;
} else if (tok.kind == TOKEN_OP_SUB) {
v1 -= v2;
} else {
UngetToken(&tok);
}
}
return v1;
}
double ParseLine()
{
double val;
stLookAheadTokExist = 0;
val = ParseExp();
return val;
}