diff --git a/Makefile b/Makefile index 14229c8..ad100c2 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ comp: lex src/lex.l yacc -d src/grammar.y - gcc -o bin/main y.tab.c lex.yy.c + gcc -o bin/main y.tab.c lex.yy.c src/summoner.c src/interpreter.c diff --git a/src/grammar.y b/src/grammar.y index 85253b4..a05fe8b 100644 --- a/src/grammar.y +++ b/src/grammar.y @@ -1,21 +1,34 @@ %{ #include #include +#include "src/summoner.h" +#include "src/interpreter.h" int yylex(); int yyerror(const char *s); %} %union { - double double_value; + double double_value; + int int_value; + struct Expression* expression; } +%token BOOL_LITERAL %token DOUBLE_LITERAL -%token CR LP RP -%left ADD SUB -%left MUL DIV +%token INT_LITERAL +%token '\n' '(' ')' -%type expr + +%left AND OR +%nonassoc EQ NE +%nonassoc '>' '<' LE GE +%left '+' '-' +%left '*' '/' +%nonassoc MINUS +%nonassoc NOT + +%type expr %% stmt_list: @@ -24,17 +37,28 @@ stmt_list: ; stmt: - expr CR { - printf(">>%lf\n", $1); - } + expr '\n' { printExprValue(evalExpression($1)); } + ; expr: - DOUBLE_LITERAL { $$ = $1; } - | expr ADD expr { $$ = $1 + $3; } - | expr SUB expr { $$ = $1 - $3; } - | expr MUL expr { $$ = $1 * $3; } - | expr DIV expr { $$ = $1 / $3; } - | LP expr RP { $$ = $2; } + INT_LITERAL { $$ = allocIntExpression($1); } + | DOUBLE_LITERAL { $$ = allocDoubleExpression($1); } + | BOOL_LITERAL { $$ = allocBoolExpression($1); } + | expr '+' expr { $$ = allocBinaryExpression(ADD_EXPRESSION, $1, $3); } + | expr '-' expr { $$ = allocBinaryExpression(SUB_EXPRESSION, $1, $3); } + | expr '*' expr { $$ = allocBinaryExpression(MUL_EXPRESSION, $1, $3); } + | expr '/' expr { $$ = allocBinaryExpression(DIV_EXPRESSION, $1, $3); } + | expr '>' expr { $$ = allocBinaryExpression(GT_EXPRESSION, $1, $3); } + | expr GE expr { $$ = allocBinaryExpression(GE_EXPRESSION, $1, $3); } + | expr '<' expr { $$ = allocBinaryExpression(LT_EXPRESSION, $1, $3); } + | expr LE expr { $$ = allocBinaryExpression(LE_EXPRESSION, $1, $3); } + | expr EQ expr { $$ = allocBinaryExpression(EQ_EXPRESSION, $1, $3); } + | expr NE expr { $$ = allocBinaryExpression(NE_EXPRESSION, $1, $3); } + | expr AND expr { $$ = allocBinaryExpression(AND_EXPRESSION, $1, $3); } + | expr OR expr { $$ = allocBinaryExpression(OR_EXPRESSION, $1, $3); } + | '!' expr %prec NOT { $$ = allocUnaryExpression(NOT_EXPRESSION, $2); } + | '(' expr ')' { $$ = $2; } + | '-' expr %prec MINUS { $$ = allocUnaryExpression(MINUS_EXPRESSION, $2); } ; %% diff --git a/src/interpreter.c b/src/interpreter.c new file mode 100644 index 0000000..1e6a3ee --- /dev/null +++ b/src/interpreter.c @@ -0,0 +1,225 @@ + +#include +#include +#include "interpreter.h" +#include "summoner.h" + +ExprValue evalIntBinaryExpression(ExpressionType type, int left, int right) +{ + ExprValue v; + v.type = EXPR_INT_VALUE; + switch (type) + { + case ADD_EXPRESSION: + v.u.int_value = left + right; + break; + case SUB_EXPRESSION: + v.u.int_value = left - right; + break; + case MUL_EXPRESSION: + v.u.int_value = left * right; + break; + case DIV_EXPRESSION: + v.u.int_value = left / right; + break; + case LT_EXPRESSION: + v.type = EXPR_BOOL_VALUE; + v.u.boolean_value = left < right; + break; + case LE_EXPRESSION: + v.type = EXPR_BOOL_VALUE; + v.u.boolean_value = left <= right; + break; + case GT_EXPRESSION: + v.type = EXPR_BOOL_VALUE; + v.u.boolean_value = left > right; + break; + case GE_EXPRESSION: + v.type = EXPR_BOOL_VALUE; + v.u.boolean_value = left >= right; + break; + case EQ_EXPRESSION: + v.type = EXPR_BOOL_VALUE; + v.u.boolean_value = left == right; + break; + case NE_EXPRESSION: + v.type = EXPR_BOOL_VALUE; + v.u.boolean_value = left != right; + break; + default: + printf("invalid expression type\n"); + exit(1); + } + return v; +} + +ExprValue evalDoubleBinaryExpression(ExpressionType type, double left, double right) +{ + ExprValue v; + v.type = EXPR_DOUBLE_VALUE; + switch (type) + { + case ADD_EXPRESSION: + v.u.double_value = left + right; + break; + case SUB_EXPRESSION: + v.u.double_value = left - right; + break; + case MUL_EXPRESSION: + v.u.double_value = left * right; + break; + case DIV_EXPRESSION: + v.u.double_value = left / right; + break; + case LT_EXPRESSION: + v.type = EXPR_BOOL_VALUE; + v.u.boolean_value = left < right; + break; + case LE_EXPRESSION: + v.type = EXPR_BOOL_VALUE; + v.u.boolean_value = left <= right; + break; + case GT_EXPRESSION: + v.type = EXPR_BOOL_VALUE; + v.u.boolean_value = left > right; + break; + case GE_EXPRESSION: + v.type = EXPR_BOOL_VALUE; + v.u.boolean_value = left >= right; + break; + case EQ_EXPRESSION: + v.type = EXPR_BOOL_VALUE; + v.u.boolean_value = left == right; + break; + case NE_EXPRESSION: + v.type = EXPR_BOOL_VALUE; + v.u.boolean_value = left != right; + break; + default: + printf("invalid expression type\n"); + exit(1); + } + return v; +} + +ExprValue evalBoolBinaryExpression(ExpressionType type, bool left, bool right) +{ + ExprValue v; + v.type = EXPR_BOOL_VALUE; + switch (type) + { + case AND_EXPRESSION: + v.u.boolean_value = left && right; + break; + case OR_EXPRESSION: + v.u.boolean_value = left || right; + break; + default: + printf("invalid expression type when eval bool value:%d\n", type); + exit(1); + } + return v; +} + +ExprValue evalBinaryExpression(ExpressionType type, BinaryExpression *binaryExpression) +{ + ExprValue leftVal = evalExpression(binaryExpression->left); + ExprValue rightVal = evalExpression(binaryExpression->right); + if (leftVal.type == EXPR_INT_VALUE && rightVal.type == EXPR_INT_VALUE) + { + return evalIntBinaryExpression(type, leftVal.u.int_value, rightVal.u.int_value); + } + + if (leftVal.type == EXPR_INT_VALUE && rightVal.type == EXPR_DOUBLE_VALUE) + { + return evalDoubleBinaryExpression(type, leftVal.u.int_value, rightVal.u.double_value); + } + + if (leftVal.type == EXPR_DOUBLE_VALUE && rightVal.type == EXPR_INT_VALUE) + { + return evalDoubleBinaryExpression(type, leftVal.u.double_value, rightVal.u.int_value); + } + + if (leftVal.type == EXPR_DOUBLE_VALUE && rightVal.type == EXPR_DOUBLE_VALUE) + { + return evalDoubleBinaryExpression(type, leftVal.u.double_value, rightVal.u.double_value); + } + + if (leftVal.type == EXPR_BOOL_VALUE && rightVal.type == EXPR_BOOL_VALUE) + { + return evalBoolBinaryExpression(type, leftVal.u.boolean_value, rightVal.u.boolean_value); + } + + printf("invalid expression type, left:%d, right:%d", leftVal.type, rightVal.type); + exit(1); +} + +ExprValue evalExpression(Expression *expr) +{ + ExprValue v; + switch (expr->type) + { + case BOOL_EXPRESSION: + v.type = EXPR_BOOL_VALUE; + v.u.boolean_value = expr->u.boolean_value; + return v; + case INT_EXPRESSION: + v.type = EXPR_INT_VALUE; + v.u.int_value = expr->u.int_value; + return v; + case DOUBLE_EXPRESSION: + v.type = EXPR_DOUBLE_VALUE; + v.u.double_value = expr->u.double_value; + return v; + case MINUS_EXPRESSION: + v = evalExpression(expr->u.unary_expression); + if (v.type == EXPR_INT_VALUE) + { + v.u.int_value = -v.u.int_value; + } + else + { + v.u.double_value = -v.u.double_value; + } + return v; + case NOT_EXPRESSION: + v = evalExpression(expr->u.unary_expression); + v.u.boolean_value = !v.u.boolean_value; + return v; + case ADD_EXPRESSION: + case SUB_EXPRESSION: + case MUL_EXPRESSION: + case DIV_EXPRESSION: + case LT_EXPRESSION: + case LE_EXPRESSION: + case GT_EXPRESSION: + case GE_EXPRESSION: + case EQ_EXPRESSION: + case NE_EXPRESSION: + case AND_EXPRESSION: + case OR_EXPRESSION: + return evalBinaryExpression(expr->type, expr->u.binary_expression); + default: + printf("invalid expression type when eval expression:%d\n", expr->type); + exit(1); + } +} + +void printExprValue(ExprValue val) +{ + switch (val.type) + { + case EXPR_INT_VALUE: + printf(">>>%d\n", val.u.int_value); + break; + case EXPR_DOUBLE_VALUE: + printf(">>>%lf\n", val.u.double_value); + break; + case EXPR_BOOL_VALUE: + printf(">>>%s\n", val.u.boolean_value ? "true" : "false"); + break; + default: + printf("invalid expression type when print expr value:%d", val.type); + exit(1); + } +} diff --git a/src/interpreter.h b/src/interpreter.h new file mode 100644 index 0000000..db0d4be --- /dev/null +++ b/src/interpreter.h @@ -0,0 +1,9 @@ +#ifndef _INTERPRETER_H_ +#define _INTERPRETER_H_ + +#include "summoner.h" + +ExprValue evalExpression(Expression *expr); +void printExprValue(ExprValue); + +#endif diff --git a/src/lex.l b/src/lex.l index 0d94f50..7adccc4 100644 --- a/src/lex.l +++ b/src/lex.l @@ -1,24 +1,41 @@ %{ #include +#include #include "y.tab.h" %} %% -"+" return ADD; -"-" return SUB; -"*" return MUL; -"/" return DIV; -"(" return LP; -")" return RP; -"\n" return CR; - -([1-9][0-9]*)|0|([0-9]+\.[0-9]+) { + +[+\-*/\(\)<>!\n] { + return *yytext; +} + +">=" return GE; +"<=" return LE; +"==" return EQ; +"!=" return NE; +"&&" return AND; +"||" return OR; + +"true"|"false" { + yylval.int_value = strcmp(yytext, "false"); + return BOOL_LITERAL; +} + +[0-9]+\.[0-9]+ { double val; sscanf(yytext, "%lf", &val); yylval.double_value = val; return DOUBLE_LITERAL; } +([1-9][0-9]*)|0 { + int val; + sscanf(yytext, "%d", &val); + yylval.int_value = val; + return INT_LITERAL; +} + [ \t] ; . { diff --git a/src/summoner.c b/src/summoner.c new file mode 100644 index 0000000..78d24a7 --- /dev/null +++ b/src/summoner.c @@ -0,0 +1,42 @@ +#include +#include +#include "summoner.h" + +Expression *allocExpression(ExpressionType type) { + Expression *expr = malloc(sizeof(Expression)); + expr->type = type; + return expr; +} + +Expression *allocIntExpression(int value) { + Expression *expr = allocExpression(INT_EXPRESSION); + expr->u.int_value = value; + return expr; +} + +Expression *allocDoubleExpression(double value) { + Expression *expr = allocExpression(DOUBLE_EXPRESSION); + expr->u.double_value = value; + return expr; +} + +Expression *allocBoolExpression(bool value) { + Expression *expr = allocExpression(BOOL_EXPRESSION); + expr->u.boolean_value = value; + return expr; +} + +Expression *allocUnaryExpression(ExpressionType type, Expression *unaryExpr) { + Expression *expr = allocExpression(type); + expr->u.unary_expression = unaryExpr; + return expr; +} + +Expression *allocBinaryExpression(ExpressionType type, Expression *left, Expression *right) { + Expression *expr = allocExpression(type); + BinaryExpression *binary = malloc(sizeof(BinaryExpression)); + binary->left = left; + binary->right = right; + expr->u.binary_expression = binary; + return expr; +} diff --git a/src/summoner.h b/src/summoner.h new file mode 100644 index 0000000..d5aef3f --- /dev/null +++ b/src/summoner.h @@ -0,0 +1,76 @@ +#ifndef _SUMMONER_H_ +#define _SUMMONER_H_ + +#include + +typedef enum +{ + EXPR_BOOL_VALUE = 1, + EXPR_INT_VALUE, + EXPR_DOUBLE_VALUE, +} ExprValueType; + +typedef struct ExprValue +{ + ExprValueType type; + union + { + bool boolean_value; + int int_value; + double double_value; + } u; + +} ExprValue; + +typedef enum +{ + BOOL_EXPRESSION = 1, + INT_EXPRESSION, + DOUBLE_EXPRESSION, + ADD_EXPRESSION, + SUB_EXPRESSION, + MUL_EXPRESSION, + DIV_EXPRESSION, + MINUS_EXPRESSION, + MOD_EXPRESSION, /* % */ + EQ_EXPRESSION, /* == */ + NE_EXPRESSION, /* != */ + GT_EXPRESSION, /* > */ + GE_EXPRESSION, /* >= */ + LT_EXPRESSION, /* < */ + LE_EXPRESSION, /* <= */ + AND_EXPRESSION, /* && */ + OR_EXPRESSION, /* || */ + NOT_EXPRESSION, /* ! */ +} ExpressionType; + +typedef struct BinaryExpression BinaryExpression; + +typedef struct Expression +{ + ExpressionType type; + union + { + bool boolean_value; + int int_value; + double double_value; + BinaryExpression *binary_expression; + struct Expression *unary_expression; + } u; + +} Expression; + +typedef struct BinaryExpression +{ + Expression *left; + Expression *right; +} BinaryExpression; + +Expression *allocExpression(ExpressionType type); +Expression *allocIntExpression(int value); +Expression *allocDoubleExpression(double value); +Expression *allocBoolExpression(bool value); +Expression *allocUnaryExpression(ExpressionType type, Expression *unaryExpr); +Expression *allocBinaryExpression(ExpressionType type, Expression *left, Expression *right); + +#endif