在windows vs2015测试通过
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
// console get line input
void getline(char* input, int inputsize) {
int len = inputsize;
int idx = 0;
input[idx] = '\0';
while (1)
{
char c = fgetc(stdin);
if (c == EOF)
break;
if (c == '\n')
{
input[idx++] = '\0';
break;
}
else {
input[idx++] = c;
}
if (idx >= len - 1)
{
input[idx++] = '\0';
break;
}
}
}
// lexical analysis section
enum tokentype
{
PLUS, MINUS, MUL, DIV, LPAREN, RPAREN, INTEGER
};
typedef struct token {
int tokentype;
char val[16];
struct token* prev;
struct token* next;
} token;
token* newtoken()
{
token* tokennew = malloc(sizeof(token));
tokennew->next = NULL;
tokennew->prev = NULL;
tokennew->val[0] = '\0';
return tokennew;
}
void tokenmoveon(token** tokencurr)
{
(*tokencurr)->next = newtoken();
(*tokencurr)->next->next = NULL;
(*tokencurr)->next->prev = (*tokencurr);
(*tokencurr) = (*tokencurr)->next;
}
void printtoknetype(int type)
{
switch (type)
{
case PLUS:
printf("PLUS");
break;
case MINUS:
printf("MINUS");
break;
case MUL:
printf("MUL");
break;
case DIV:
printf("DIV");
break;
case LPAREN:
printf("LPAREN");
break;
case RPAREN:
printf("RPAREN");
break;
case INTEGER:
printf("INTEGER");
break;
default:
break;
}
}
void printtoken(token* thead)
{
token* p;
p = thead;
printf("tokne:\n");
while (p != NULL)
{
printtoknetype(p->tokentype);
printf(":[%s] ", p->val);
p = p->next;
}
printf("\n");
}
void tokenone(token** tokencurr, int tokentype, char op)
{
(*tokencurr)->tokentype = tokentype;
(*tokencurr)->val[0] = op;
(*tokencurr)->val[1] = '\0';
tokenmoveon(tokencurr);
}
token* tokenize(char* str)
{
if (!*str) printf("no token\n");
token* thead;
token* tokencurr = newtoken();
thead = tokencurr;
int i, idx = 0;
char word[16];
for (i = 0; i < strlen(str); i++) {
char next = str[i + 1];
switch (str[i])
{
case ' ':
continue;
case '\0':
break;
case '+': //after + will be num (after num will be a op) or (
tokenone(&tokencurr, PLUS, '+');
continue;
case '-':
tokenone(&tokencurr, MINUS, '-');
continue;
case '*':
tokenone(&tokencurr, MUL, '*');
continue;
case '/':
tokenone(&tokencurr, DIV, '/');
continue;
case '(':
tokenone(&tokencurr, LPAREN, '(');
continue;
case ')':
tokenone(&tokencurr, RPAREN, ')');
continue;
default:
word[idx++] = str[i]; // digit num
if (!isdigit(next)) // finish num
{
word[idx] = '\0';
strcpy(tokencurr->val, word);
idx = 0;
tokencurr->tokentype = INTEGER;
tokenmoveon(&tokencurr);
}
continue;
}
}
//delete last token, is null token, because we tokenmoveon create token node first
tokencurr = tokencurr->prev;
free(tokencurr->next);
tokencurr->next = NULL;
return thead;
}
// syntax analysis section
typedef struct node {
token* val; //op or num token, num node is leaf
struct node* left; // when this is op node
struct node* right;
} node;
node* newnode()
{
node* nodenew = malloc(sizeof(node));
nodenew->val = NULL;
nodenew->left = NULL;
nodenew->right = NULL;
return nodenew;
}
// syntax directed translation, each grammar is a function
/*
expr : term ((PLUS | MINUS) term)*
term : factor ((MUL | DIV) factor)*
factor : INTEGER | LPAREN expr RPAREN
*/
token* tokenp; //token list index pointer
node* factor();
node* term();
node* expr();
node* factor()
{
if (tokenp->tokentype == INTEGER) // find num
{
node* one = newnode();
one->val = tokenp;
tokenp = tokenp->next;//skip num
return one;
}
else if (tokenp->tokentype == LPAREN) //find (), to recursive descent parse
{
tokenp = tokenp->next;//skip LP
node* one = expr(); // recursive, exit if the token is RPARENT, otherwise if match other token like integer or +-/* will be still in the recursive
tokenp = tokenp->next; //skip RP
return one;
}
}
node* term()
{
node* one = factor();
while (tokenp!=NULL && (tokenp->tokentype == MUL || tokenp->tokentype == DIV))
{
node* op = newnode();
op->val = tokenp;
op->left = one;
tokenp = tokenp->next; //skip * or /
op->right = factor();
one = op;
}
return one;
}
node* expr()
{
node* one = term();
/*
e.g. 1+2+3+4
this will first create
+
/\
1 2
then, add + 3 at the top,
+
/\
+ 3
/\
1 2
1+2*3 like
+
/\
1 *
/\
2 3
because plus->right = term(), and term is 2*3
*/
while (tokenp!=NULL && (tokenp->tokentype == PLUS || tokenp->tokentype == MINUS))
{
node* op = newnode();
op->val = tokenp;
op->left = one;
tokenp = tokenp->next; //skip + or -
op->right = term();
one = op;
}
return one;
}
//low order in the bottom of tree
//same order from bottom left to top right tree
node* ast(token* tokenlist)
{
tokenp = tokenlist;
return expr();
}
int calc(int a, int b, char op)
{
switch (op)
{
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
return a / b;
}
}
//the node is oprator +-/*
int isop(int tokentype)
{
if (tokentype == PLUS
|| tokentype == MINUS
|| tokentype == MUL
|| tokentype == DIV)
{
return 1;
}
return 0;
}
//postorder traversal
int eval(node* nodelist)
{
int left=0, right=0;
if (isop(nodelist->val->tokentype))
{
if (isop(nodelist->left->val->tokentype))
{
left=eval(nodelist->left);
}
if (isop(nodelist->right->val->tokentype))
{
right=eval(nodelist->right);
}
}
//if nodelist->left->val->val is not a integer, like +-*/, not a integer ascii atoi will return 0
return calc(atoi(nodelist->left->val->val)+left, atoi(nodelist->right->val->val)+right, nodelist->val->val[0]);
}
int main()
{
char input[128];
getline(input, 128);
token* tokenlist = tokenize(input);
printtoken(tokenlist);
node* nodelist = ast(tokenlist);
int res = eval(nodelist);
printf("res:%d\n", res);
return 0;
}
/*
1+2+3+4*5*6*7-8-9 tree view
-
/ \
- 9
/ \
+ 8
/ \
+ *
/\ /\
+ 3 * 7
/\ /\
1 2 * 6
/\
4 5
first 1+2,then +3, then + with plus->right = term() to get all 4*5*6*7
first 4*5,then *6,*7, then add the node to +
then -8, -9
*/