使用手工的方式编写一个简易的计算器,首先手工实现词法的解析。
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_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
lex.c
#include "lex.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
static char *sLine;
static int sLinePos;
typedef enum {
INIT_ST,
INT_PART_ST,
DOT_ST,
FRAC_PART_ST,
} LexerStatus;
void GetToken(Token *token)
{
int pos = 0;
LexerStatus st = INIT_ST;
char currChar;
token->kind = TOKEN_BAD;
while (sLine[sLinePos] != '\0') {
currChar = sLine[sLinePos];
// extract number
if ((st == INT_PART_ST || st == FRAC_PART_ST)
&& !isdigit(currChar) && currChar != '.') {
token->kind = TOKEN_NUM;
sscanf(token->str, "%lf", &token->value);
return ;
}
// skip space
if (isspace(currChar)) {
if (currChar == '\n') {
token->kind = TOKEN_LINE_END;
return ;
}
sLinePos++;
continue;
}
if (sLinePos >= MAX_TOKEN_SIZE - 1) {
fprintf(stderr, "token too long \n");
}
token->str[pos] = sLine[sLinePos];
sLinePos++;
pos++;
token->str[pos] = '\0';
if (currChar == '+')
{
token->kind = TOKEN_OP_ADD;
return ;
} else if (currChar == '-') {
token->kind = TOKEN_OP_SUB;
return ;
} else if (currChar == '*') {
token->kind = TOKEN_OP_MUL;
return ;
} else if (currChar == '/') {
token->kind = TOKEN_OP_DIV;
return ;
} else if (isdigit(currChar)) {
if (st == INIT_ST) {
st = INT_PART_ST;
} else if (st == DOT_ST) {
st = FRAC_PART_ST;
}
} else if (currChar == '.') {
if (st == INT_PART_ST) {
st = DOT_ST;
} else {
fprintf(stderr, "syntax error. \n");
exit(1);
}
} else {
fprintf(stderr, "bad charactor(%c)\n", currChar);
exit(1);
}
}
}
void SetLine(char *line)
{
sLine = line;
sLinePos = 0;
}
// test code
void ParseLine(char *buf)
{
Token token;
SetLine(buf);
while (1) {
GetToken(&token);
if (token.kind == TOKEN_LINE_END) {
break;
} else {
printf("kind : %d -- %s \n", token.kind, token.str);
}
}
}
int main(int argc, char **argv)
{
char buf[1024];
while (fgets(buf, 1024, stdin) != NULL) {
printf("Parse String: %s", buf);
ParseLine(buf);
}
return 0;
}