@@ -43,13 +43,14 @@ SymbolTable *table = new SymbolTable();
// useful for debugging
void verbose(const char* msg) {
char buffer[256] = "";
sprintf(buffer,"parser@%i: " BLUE "\"%s\"" CLEAR_FORMAT "\n", line, msg);
sprintf(buffer,"parser@%i: " BLUE "%s" CLEAR_FORMAT "\n", line, msg);
fprintf(stdout,buffer);
fflush(stdout);
}

// formats error messages
void p_error(const char* msg) {
fprintf(stderr,"parser@%i: syntax error " RED "\"%s\"" CLEAR_FORMAT "\n" ,line,msg);
fprintf(stderr,"parser@%i: syntax error " RED "%s" CLEAR_FORMAT "\n" ,line,msg);
}

// oneliner for checking if token is type keyword
@@ -64,7 +65,6 @@ bool is_type(int token) {
token == DOUBLE ||
token == BOOL ||
token == VOID;
//TODO: are bool and void not types?
}

// oneliner for checking if token is a numeric operator
@@ -94,17 +94,17 @@ int expect(int expected, bool type=false) {
int next = yylex();
if(type) { // ignore expected
if(!is_type(next)) {
sprintf(err_buff,"unexpected token %s (code %i); expected a type",
yytext,next);
sprintf(err_buff,"(%i)unexpected token %s (code %i); expected a type",
__LINE__,yytext,next);
p_error(err_buff);
if(yytext) free(yytext);
return PARSE_ERR;
}
return next; // type
}
else if(next != expected) {
sprintf(err_buff,"unexpected token %s (code %i); expected %i",
yytext,next,expected);
sprintf(err_buff,"(%i)unexpected token %s (code %i); expected %i",
__LINE__,yytext,next,expected);
p_error(err_buff);
if(yytext) free(yytext);
return PARSE_ERR;
@@ -139,11 +139,15 @@ int expression(int prev) {
/*==============================================*/

int main(int argc, char *argv[]) {
//TODO
if(argc>1)
if((yyin = fopen(argv[1],"r")) == NULL)
return -1;
verbose("diving into the parse tree");
int ret = start();

fflush(stdout);
printf("return: %i\nState of the symbol table:\n",ret);
table->print();
return start();
}

@@ -174,23 +178,26 @@ int program() {
int next = yylex(), peek;
while(next != MAIN) {
/* verify declaration correct */
verbose("still not main");
if(is_type(next)) {
verbose("perceived type keyword");
if(declaration(next,&peek) == PARSE_ERR)
return PARSE_ERR;
next = peek; // in declaration we looked +1 ahead
verbose("declarations++");
}
/* verify definition correct */
else if(next == FUNC) {
verbose("perceived function keyword");
if(definition() == PARSE_ERR)
return PARSE_ERR;
next = yylex();
verbose("definitions++");
}
/* not main and not the previous */
else {
sprintf(err_buff,"unexpected token %s (code %i)",
yytext,next);
sprintf(err_buff,"(%i)unexpected token %s (code %i)",
__LINE__,yytext,next);
p_error(err_buff);
return PARSE_ERR;
}
@@ -215,7 +222,7 @@ int declaration(int prev, int *looked) {
return PARSE_ERR;

//TODO: fix
table->store_symbol(prev, VAR_T, 0, yylval.sval);
table->store_symbol(VAR_T, prev, 0, yylval.sval);

next = yylex();
if(next != ARROW) {
@@ -236,32 +243,38 @@ int declaration(int prev, int *looked) {
*/
int definition() {
int ret,next,num_args=0;

if(expect(ID) == PARSE_ERR) //identifier
return PARSE_ERR;
verbose("processed: identifier");
/* save the name */
char *name = strdup(yylval.sval);
verbose(name);

if(expect(':') == PARSE_ERR) //:
return PARSE_ERR;
verbose("processed: ':'");

if((ret = expect(0,true)) == PARSE_ERR) //type
return PARSE_ERR;
verbose("processed: return type");

if(expect(ARROW) == PARSE_ERR) //<-
return PARSE_ERR;

/* ambiguity! */
next = yylex();
while(next != '{') { /* still not the code */
verbose("processed: argument");
if(argument(next) == PARSE_ERR)
return PARSE_ERR;
num_args++;
next = yylex();
}
// everything ok up to here, so we register the function
func_counter++;
table->set_scope(++func_counter);
//TODO: set the correct scope (or number) of the function
table->store_symbol(ret, FUNC_T, num_args, name);
table->store_symbol(FUNC_T, ret, num_args, name);

return code(ret);
}
@@ -307,157 +320,175 @@ int mn() {
* '{' {better see the grammar for this rule} '}'
*/
int code(int ret) {
//TODO
int first = yylex();
int plus_or_minus = first; // if we save the + / - we can avoid repeating their code twice
SymbolRegister *found = table->get_symbol(yylval.sval); // let's get this out of the way
// TODO: lacking a while, are we?
// TODO: also, lacking variable declarations!
// TODO: also, lacking closing '}'
// or maybe recursion, but that could be bad
switch(first) {
/* the incrementor and decrementor operators: *
* we have to check for the "twin", and if not *
* found the expression makes no sense */
case '+':
case '-':
first = yylex();
if(first == plus_or_minus) {
while(first != '}') {
sprintf(err_buff,"next statement: starts with %s",yytext);
verbose(err_buff);
switch(first) {
/* the incrementor and decrementor operators: *
* we have to check for the "twin", and if not *
* found the expression makes no sense */
case '+':
case '-':
first = yylex();
if(first != ID) {
p_error("the increment operator only works on variables");
return PARSE_ERR;
} else if(!(found = table->get_symbol(yylval.sval))) {
sprintf(err_buff,"%s was not previously declared",yylval.sval);
if(first == plus_or_minus) {
first = yylex();
if(first != ID) {
sprintf(err_buff,"(%i)the increment operator only works on variables",
__LINE__);
p_error(err_buff);
return PARSE_ERR;
} else if(!(found = table->get_symbol(yylval.sval))) {
sprintf(err_buff,"(%i)%s was not previously declared",
__LINE__,yylval.sval);
p_error(err_buff);
return PARSE_ERR;
} else if(found->get_type() != INT) {
sprintf(err_buff,"(%i)the decrement/increment operator only works on variables of integer type",
__LINE__);
p_error(err_buff);
return PARSE_ERR;
} else {
// do your increment magic here
}
} else {
sprintf(err_buff,"(%i)the only allowed statement that starts with '%c' is a decrement of a variable",
__LINE__,plus_or_minus);
p_error(err_buff);
return PARSE_ERR;
} else if(found->get_type() != INT) {
p_error("the decrement/increment operator only works on variables of integer type");
return PARSE_ERR;
} else {
// do your increment magic here
}
} else {
sprintf(err_buff,"the only allowed statement that starts with '%c' is a decrement of a variable",
plus_or_minus);
p_error(err_buff);
return PARSE_ERR;
}
case ID:
/* a call or an assignment */
int type;
if(!found) {
sprintf(err_buff,"%s was not previously declared",yylval.sval);
p_error(err_buff);
return PARSE_ERR;
} else if ((type = found->get_type())== FUNC_T) {
//in this instance we don't need to check the return type... nobody is expecting it!
if(call() == PARSE_ERR)
return PARSE_ERR;
break; // will this break out of the switch, or the while?
} else if (type == VAR_T || type == ARG_T) {
// look for asignment
if(expect(ARROW) == PARSE_ERR)
return PARSE_ERR;
//TODO: missing the SCAN possibility... ought to peek one more
int expected_ret = found->get_return(),
parsed_ret;
if(nexp(-1,&parsed_ret) == PARSE_ERR)
return PARSE_ERR;
if(expected_ret != parsed_ret) {
sprintf(err_buff,"trying to assign a %i value to %s, which is of type %i",
parsed_ret,found->get_name(),expected_ret);
case ID:
/* a call or an assignment */
int type;
if(!found) {
sprintf(err_buff,"(%i)%s was not previously declared",
__LINE__,yylval.sval);
p_error(err_buff);
return PARSE_ERR;
} else if ((type = found->get_type())== FUNC_T) {
//in this instance we don't need to check the return type... nobody is expecting it!
if(call() == PARSE_ERR)
return PARSE_ERR;
break; // will this break out of the switch, or the while?
} else if (type == VAR_T || type == ARG_T) {
// look for asignment
if(expect(ARROW) == PARSE_ERR)
return PARSE_ERR;
//TODO: missing the SCAN possibility... ought to peek one more
int expected_ret = found->get_return(),
parsed_ret;
if(nexp(-1,&parsed_ret) == PARSE_ERR)
return PARSE_ERR;
if(expected_ret != parsed_ret) {
sprintf(err_buff,"(%i)trying to assign a %i value to %s, which is of type %i",
__LINE__,parsed_ret,found->get_name(),expected_ret);
p_error(err_buff);
return PARSE_ERR;
}
break;
}
break;
}
return PARSE_ERR;
case IF:
if(bexp(-1) == PARSE_ERR) // check for the condition
return PARSE_ERR;
if(expect('{') == PARSE_ERR) {
p_error("sorry, but conditional statements must be surrounded by curly brackets");
}
if(code(-1) == PARSE_ERR) // consumes the closing '}'
return PARSE_ERR;
first = yylex(); // look ahead for ELSE
if(first == ELSE) {
case IF:
if(bexp(-1) == PARSE_ERR) // check for the condition
return PARSE_ERR;
if(expect('{') == PARSE_ERR) {
p_error("sorry, but conditional statements must be surrounded by curly brackets");
}
if(code(-1) == PARSE_ERR) // consumes the closing '}'
return PARSE_ERR;
}
break; // next token already fetched
case WHILE:
/* include here bexpr, the '{' code '}' */
if(bexp(-1) == PARSE_ERR) // check for the condition
return PARSE_ERR;
if(expect('{') == PARSE_ERR) {
p_error("sorry, but conditional statements must be surrounded by curly brackets");
}
if(code(-1) == PARSE_ERR) // consumes the closing '}'
return PARSE_ERR;
first = yylex(); // done with this statement
break; // next token already fetched
case PRINT:
/* parse '(' parameter* ')' */
/* or... could I just use call()? as long as it processes the arguments correctly...
* if it becomes hellish to put the arguments into the object, just copy the code */
if(call() == PARSE_ERR)
return PARSE_ERR;
first = yylex(); // done with this statement
case RET:
/* several things here:
* -check for parameter, and for type correctness *
* -also, throw error if func is not VOID and no *
* parameters are found *
* -check for '}': ret is final to a code block *
* -if not found, print error and iterate *
* through tokens until one is found (doing *
* nothing with them) and see what happens */
if(ret == VOID) {
if(expect('}') == PARSE_ERR) {
p_error("returning something in a void function!");
first = yylex(); // look ahead for ELSE
if(first == ELSE) {
if(expect('{') == PARSE_ERR) {
p_error("sorry, but conditional statements must be surrounded by curly brackets");
}
if(code(-1) == PARSE_ERR) // consumes the closing '}'
return PARSE_ERR;
}
break; // next token already fetched
case WHILE:
/* include here bexpr, the '{' code '}' */
if(bexp(-1) == PARSE_ERR) // check for the condition
return PARSE_ERR;
if(expect('{') == PARSE_ERR) {
p_error("sorry, but conditional statements must be surrounded by curly brackets");
}
} else {
first = yylex();
if(first == ID) { // identifier or call?
found = table->get_symbol(yylval.sval);
if(!found) {
sprintf(err_buff,"%s was not previously declared",yylval.sval);
p_error(err_buff);
return PARSE_ERR;
} else if(found->get_return() != ret) { // return type coherence check
sprintf(err_buff,"expected %i return type: %s is of %i type",
ret,found->get_name(),found->get_return());
if(code(-1) == PARSE_ERR) // consumes the closing '}'
return PARSE_ERR;
first = yylex(); // done with this statement
break; // next token already fetched
case PRINT:
/* parse '(' parameter* ')' */
/* or... could I just use call()? as long as it processes the arguments correctly...
* if it becomes hellish to put the arguments into the object, just copy the code */
if(call() == PARSE_ERR)
return PARSE_ERR;
first = yylex(); // done with this statement
case RET:
/* several things here:
* -check for parameter, and for type correctness *
* -also, throw error if func is not VOID and no *
* parameters are found *
* -check for '}': ret is final to a code block *
* -if not found, print error and iterate *
* through tokens until one is found (doing *
* nothing with them) and see what happens */
if(ret == VOID) {
if(expect('}') == PARSE_ERR) {
sprintf(err_buff,"(%i)returning something in a void function!",__LINE__);
p_error(err_buff);
return PARSE_ERR;
} else if(found->get_type()== FUNC_T) {
if(call() == PARSE_ERR)
return PARSE_ERR;
break;
} else { // ARG_T / VAR_T, but we don't quite care
break;
}
} else if(expression(first) == PARSE_ERR) // also, gotta check return type
return PARSE_OK;
} else {
first = yylex();
if(first == ID) { // identifier or call?
found = table->get_symbol(yylval.sval);
if(!found) {
sprintf(err_buff,"(%i)%s was not previously declared",
__LINE__,yylval.sval);
p_error(err_buff);
return PARSE_ERR;
} else if(found->get_return() != ret) { // return type coherence check
sprintf(err_buff,"(%i)expected %i return type: %s is of %i type",
__LINE__,ret,found->get_name(),found->get_return());
p_error(err_buff);
return PARSE_ERR;
} else if(found->get_type()== FUNC_T) {
if(call() == PARSE_ERR)
return PARSE_ERR;
break;
} else { // ARG_T / VAR_T, but we don't quite care
break;
}
} else if(expression(first) == PARSE_ERR) // also, gotta check return type
return PARSE_ERR;
return PARSE_OK;
}
case EXIT:
/* drop_until_brace takes care of things and effectively
* consumes the closing bracket (if found)*/
if(drop_until_brace() == PARSE_ERR)
return PARSE_ERR;
return PARSE_OK;
}
case EXIT:
/* drop_until_brace takes care of things and effectively
* consumes the closing bracket (if found)*/
if(drop_until_brace() == PARSE_ERR)
return PARSE_ERR;
return PARSE_OK;
default: /* epsilon case is actually taken care of beforehand */
sprintf(err_buff,"unexpected token %s (code %i)",
yytext,first);
p_error(err_buff);
return PARSE_ERR;

default: /* check for variable declarations, and if not, well, wtf */
if(!is_type(first)) {
sprintf(err_buff,"(%i)unexpected token %s (code %i)",
__LINE__,yytext,first);
p_error(err_buff);
return PARSE_ERR;
}
if(declaration(first,&first) == PARSE_ERR)
return PARSE_ERR;
sprintf(err_buff,"(%i)token after declaration: %s",
__LINE__,yytext);
verbose(err_buff);
}
}
return PARSE_ERR;
}
@@ -478,6 +509,8 @@ int nexp(int prev, int *ret_type) {
int func_or_var;
SymbolRegister *got = NULL;
switch(prev) {
case ARROW:
return nexp(yylex(),ret_type);
case INT_N:
*ret_type = INT;
return PARSE_OK;
@@ -489,7 +522,8 @@ int nexp(int prev, int *ret_type) {
case ID:
got = table->get_symbol(yylval.sval);
if(!got) { /* not even in the table */
sprintf(err_buff,"%s was not declared",yylval.sval);
sprintf(err_buff,"(%i)%s was not declared",
__LINE__,yylval.sval);
p_error(err_buff);
return PARSE_ERR;
} else { /* in the table: let's check type */
@@ -620,19 +654,14 @@ int bexp(int prev) {
*/
int argument(int prev) {
/* lex has been called already! */
/* save the name */
int type;
char *name = strdup(yylval.sval);
int type = prev;

if(expect(':') == PARSE_ERR) {
free(name);
if(expect(':') == PARSE_ERR)
return PARSE_ERR;
}

if((type = expect(0,true)) == PARSE_ERR) {
free(name);
if(expect(ID) == PARSE_ERR)
return PARSE_ERR;
}
char *name = strdup(yylval.sval);

table->store_symbol(ARG_T,type,0,name); //TODO: FIX
free(name);
@@ -87,7 +87,8 @@ char* SymbolRegister::get_name() {

void SymbolRegister::print() {
char *type = names(this->ret);
fprintf(stdout,"%s %s:%s (%i)\n",
fprintf(stdout,"(%i)%s %s:%s (%i)\n",
this->type,
(this->type == VAR_T)?"variable":(this->type == FUNC_T)?"function":"argument",
this->name,
type,
@@ -131,23 +132,20 @@ void SymbolTable::store_symbol(int type, int ret, int info, char* name) {
this->size++;
}

SymbolRegister* SymbolTable::get_symbol(char* name) {
SymbolRegister* SymbolTable::get_symbol(char* name, unsigned int scope) {
SymbolRegister* follower = this->head;

while(follower) {
if(strcmp(follower->get_name(),name) == 0)
return follower;
if(follower->get_level() == scope)
return follower;
follower = follower->next;
}
return NULL;
}

void SymbolTable::push_scope() {
this->scope++;
}

void SymbolTable::pop_scope() {
this->scope--;
void SymbolTable::set_scope(unsigned int scope) {
this->scope = scope;
}

unsigned int SymbolTable::get_scope() {