-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
94e7925
commit 8efabc0
Showing
6 changed files
with
320 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/* | ||
* Expression.c | ||
* Implementation of functions used to build the syntax tree. | ||
*/ | ||
|
||
#include "Expression.h" | ||
|
||
#include <stdlib.h> | ||
|
||
/** | ||
* @brief Allocates space for expression | ||
* @return The expression or NULL if not enough memory | ||
*/ | ||
static SExpression *allocateExpression() | ||
{ | ||
SExpression *b = (SExpression *)malloc(sizeof(SExpression)); | ||
|
||
if (b == NULL) | ||
return NULL; | ||
|
||
b->type = eVALUE; | ||
b->value = 0; | ||
|
||
b->left = NULL; | ||
b->right = NULL; | ||
|
||
return b; | ||
} | ||
|
||
SExpression *createNumber(int value) | ||
{ | ||
SExpression *b = allocateExpression(); | ||
|
||
if (b == NULL) | ||
return NULL; | ||
|
||
b->type = eVALUE; | ||
b->value = value; | ||
|
||
return b; | ||
} | ||
|
||
SExpression *createOperation(EOperationType type, SExpression *left, SExpression *right) | ||
{ | ||
SExpression *b = allocateExpression(); | ||
|
||
if (b == NULL) | ||
return NULL; | ||
|
||
b->type = type; | ||
b->left = left; | ||
b->right = right; | ||
|
||
return b; | ||
} | ||
|
||
void deleteExpression(SExpression *b) | ||
{ | ||
if (b == NULL) | ||
return; | ||
|
||
deleteExpression(b->left); | ||
deleteExpression(b->right); | ||
|
||
free(b); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
* Expression.h | ||
* Definition of the structure used to build the syntax tree. | ||
*/ | ||
#ifndef __EXPRESSION_H__ | ||
#define __EXPRESSION_H__ | ||
|
||
/** | ||
* @brief The operation type | ||
*/ | ||
typedef enum tagEOperationType | ||
{ | ||
eVALUE, | ||
eMULTIPLY, | ||
ePLUS | ||
} EOperationType; | ||
|
||
/** | ||
* @brief The expression structure | ||
*/ | ||
typedef struct tagSExpression | ||
{ | ||
EOperationType type;///< type of operation | ||
|
||
int value;///< valid only when type is eVALUE | ||
struct tagSExpression *left; ///< left side of the tree | ||
struct tagSExpression *right;///< right side of the tree | ||
} SExpression; | ||
|
||
/** | ||
* @brief It creates an identifier | ||
* @param value The number value | ||
* @return The expression or NULL in case of no memory | ||
*/ | ||
SExpression *createNumber(int value); | ||
|
||
/** | ||
* @brief It creates an operation | ||
* @param type The operation type | ||
* @param left The left operand | ||
* @param right The right operand | ||
* @return The expression or NULL in case of no memory | ||
*/ | ||
SExpression *createOperation(EOperationType type, SExpression *left, SExpression *right); | ||
|
||
/** | ||
* @brief Deletes a expression | ||
* @param b The expression | ||
*/ | ||
void deleteExpression(SExpression *b); | ||
|
||
#endif // __EXPRESSION_H__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
%{ | ||
|
||
/* | ||
* Lexer.l file | ||
* To generate the lexical analyzer run: "flex Lexer.l" | ||
*/ | ||
|
||
#include "Expression.h" | ||
#include "Parser.h" | ||
|
||
#include <stdio.h> | ||
|
||
%} | ||
|
||
%option outfile="Lexer.c" header-file="Lexer.h" | ||
%option warn nodefault | ||
|
||
%option reentrant noyywrap never-interactive nounistd | ||
%option bison-bridge | ||
|
||
LPAREN "(" | ||
RPAREN ")" | ||
PLUS "+" | ||
MULTIPLY "*" | ||
|
||
NUMBER [0-9]+ | ||
WS [ \r\n\t]* | ||
|
||
%% | ||
|
||
{WS} { /* Skip blanks. */ } | ||
{NUMBER} { sscanf(yytext, "%d", &yylval->value); return TOKEN_NUMBER; } | ||
|
||
{MULTIPLY} { return TOKEN_MULTIPLY; } | ||
{PLUS} { return TOKEN_PLUS; } | ||
{LPAREN} { return TOKEN_LPAREN; } | ||
{RPAREN} { return TOKEN_RPAREN; } | ||
. { } | ||
|
||
%% | ||
|
||
int yyerror(const char *msg) { | ||
fprintf(stderr,"Error:%s\n",msg); return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Makefile | ||
|
||
FILES = Lexer.c Parser.c Expression.c main.c | ||
CC = g++ | ||
CFLAGS = -g -ansi | ||
|
||
test: $(FILES) | ||
$(CC) $(CFLAGS) $(FILES) -o test | ||
|
||
Lexer.c: Lexer.l | ||
flex Lexer.l | ||
|
||
Parser.c: Parser.y Lexer.c | ||
bison Parser.y | ||
|
||
clean: | ||
rm -f *.o *~ Lexer.c Lexer.h Parser.c Parser.h test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
%{ | ||
|
||
/* | ||
* Parser.y file | ||
* To generate the parser run: "bison Parser.y" | ||
*/ | ||
|
||
#include "Expression.h" | ||
#include "Parser.h" | ||
#include "Lexer.h" | ||
#include <iostream> | ||
|
||
int yyerror(SExpression **expression, yyscan_t scanner, const char *msg) | ||
{ | ||
// Add error handling routine as needed | ||
std::cerr << msg << std::endl; | ||
return 0; | ||
} | ||
|
||
%} | ||
|
||
%code requires { | ||
|
||
#ifndef YY_TYPEDEF_YY_SCANNER_T | ||
#define YY_TYPEDEF_YY_SCANNER_T | ||
typedef void* yyscan_t; | ||
#endif | ||
|
||
} | ||
|
||
%output "Parser.c" | ||
%defines "Parser.h" | ||
|
||
%define api.pure | ||
%lex-param { yyscan_t scanner } | ||
%parse-param { SExpression **expression } | ||
%parse-param { yyscan_t scanner } | ||
|
||
%union { | ||
int value; | ||
SExpression *expression; | ||
} | ||
|
||
%left '+' TOKEN_PLUS | ||
%left '*' TOKEN_MULTIPLY | ||
|
||
%token TOKEN_LPAREN | ||
%token TOKEN_RPAREN | ||
%token TOKEN_PLUS | ||
%token TOKEN_MULTIPLY | ||
%token <value> TOKEN_NUMBER | ||
|
||
%type <expression> expr | ||
|
||
%% | ||
|
||
input | ||
: expr { *expression = $1; } | ||
; | ||
|
||
expr | ||
: expr[L] TOKEN_PLUS expr[R] { $$ = createOperation( ePLUS, $L, $R ); } | ||
| expr[L] TOKEN_MULTIPLY expr[R] { $$ = createOperation( eMULTIPLY, $L, $R ); } | ||
| TOKEN_LPAREN expr[E] TOKEN_RPAREN { $$ = $E; } | ||
| TOKEN_NUMBER { $$ = createNumber($1); } | ||
; | ||
|
||
%% |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/* | ||
* main.c file | ||
*/ | ||
|
||
#include "Expression.h" | ||
#include "Parser.h" | ||
#include "Lexer.h" | ||
|
||
#include <stdio.h> | ||
|
||
int yyparse(SExpression **expression, yyscan_t scanner); | ||
|
||
SExpression *getAST(const char *expr) | ||
{ | ||
SExpression *expression; | ||
yyscan_t scanner; | ||
YY_BUFFER_STATE state; | ||
|
||
if (yylex_init(&scanner)) { | ||
// could not initialize | ||
return NULL; | ||
} | ||
|
||
state = yy_scan_string(expr, scanner); | ||
|
||
if (yyparse(&expression, scanner)) { | ||
// error parsing | ||
return NULL; | ||
} | ||
|
||
yy_delete_buffer(state, scanner); | ||
|
||
yylex_destroy(scanner); | ||
|
||
return expression; | ||
} | ||
|
||
int evaluate(SExpression *e) | ||
{ | ||
switch (e->type) { | ||
case eVALUE: | ||
return e->value; | ||
case eMULTIPLY: | ||
return evaluate(e->left) * evaluate(e->right); | ||
case ePLUS: | ||
return evaluate(e->left) + evaluate(e->right); | ||
default: | ||
// should not be here | ||
return 0; | ||
} | ||
} | ||
|
||
void test(const char* text) | ||
{ | ||
SExpression *e = NULL; | ||
|
||
e = getAST(text); | ||
|
||
int result = evaluate(e); | ||
|
||
printf("Result of '%s' is %d\n", text, result); | ||
|
||
deleteExpression(e); | ||
|
||
} | ||
|
||
int main(void) | ||
{ | ||
test("4 ~ 3"); | ||
test("4 + 3"); | ||
test("4 + 2"); | ||
return 0; | ||
} |