Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -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
52 changes: 38 additions & 14 deletions src/grammar.y
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
%{
#include <stdio.h>
#include <stdlib.h>
#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 <int_value> BOOL_LITERAL
%token <double_value> DOUBLE_LITERAL
%token CR LP RP
%left ADD SUB
%left MUL DIV
%token <int_value> INT_LITERAL
%token '\n' '(' ')'

%type <double_value> expr

%left AND OR
%nonassoc EQ NE
%nonassoc '>' '<' LE GE
%left '+' '-'
%left '*' '/'
%nonassoc MINUS
%nonassoc NOT

%type <expression> expr

%%
stmt_list:
Expand All @@ -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); }
;
%%

Expand Down
225 changes: 225 additions & 0 deletions src/interpreter.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@

#include <stdio.h>
#include <stdlib.h>
#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);
}
}
9 changes: 9 additions & 0 deletions src/interpreter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef _INTERPRETER_H_
#define _INTERPRETER_H_

#include "summoner.h"

ExprValue evalExpression(Expression *expr);
void printExprValue(ExprValue);

#endif
35 changes: 26 additions & 9 deletions src/lex.l
Original file line number Diff line number Diff line change
@@ -1,24 +1,41 @@
%{
#include <stdio.h>
#include <string.h>
#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] ;

. {
Expand Down
Loading