platypus/parser.c

875 lines
20 KiB
C

/* File Name: parser.c
* The PLATYPUS parsing program for the final assignment of
How To Train Your Dragon (AKA Compilers)
* Compiler: GNU GCC 6
* Author: Victor Fernandes, 040772243
* Course: CST8152 - Compilers, Lab Section: 011
* Date: April 21, 2017
* Professor: Svillen Ravev
* Version: 0.1
*/
#include "parser.h"
/* Global variables for the parser */
Token lookahead;
int synerrno; /* Error counter */
Buffer *sc_buf; /* Scanner buffer */
extern char *kw_table[]; /* Keyword table with matching enum */
extern STD sym_table; /* The symbol table */
extern Buffer *str_LTBL; /* String literal table */
extern int line; /* Line position of the Scanner */
extern Token malar_next_token(Buffer *); /* Scanner function to get the next token */
/* Begins the source file parsing
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: malar_next_token, program, match, gen_incode
* Parameters: pBuffer - The input buffer
* Return value: N/A
*/
void parser(pBuffer in_buf)
{
synerrno = 0;
sc_buf = in_buf;
lookahead = malar_next_token(sc_buf);
program();
match(SEOF_T, NO_ATTR);
gen_incode("PLATY: Source file parsed");
}
/* Matches the given token code+attribute pair to the current lookahead token
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: syn_eh, syn_printe, malar_next_token
* Parameters: pr_token_code, pr_token_attribute
* Return value:
* Algorithm:
*/
void match(int pr_token_code, int pr_token_attribute)
{
if (pr_token_code != lookahead.code)
{
syn_eh(pr_token_code);
return;
}
switch (pr_token_code)
{
case ART_OP_T:
case REL_OP_T:
case LOG_OP_T:
case KW_T:
if (pr_token_attribute != lookahead.attribute.get_int)
{
break;
}
default:
if (lookahead.code == SEOF_T)
return;
lookahead = malar_next_token(sc_buf);
if (lookahead.code == ERR_T)
{
++synerrno;
syn_printe();
lookahead = malar_next_token(sc_buf);
}
return;
}
syn_eh(pr_token_code);
}
/* Error "recovery" function for the parser
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: syn_printe, malar_next_token, exit
* Parameters: int pr_token_code
* Return value:
* Algorithm: Outputs a standard syn_printe error, and steps through
the source file with the Scanner until it finds the next matching
code needed by pr_token_code.
*/
void syn_eh(int pr_token_code)
{
syn_printe();
++synerrno;
while (lookahead.code != SEOF_T)
{
lookahead = malar_next_token(sc_buf);
if (lookahead.code == pr_token_code)
{
if (lookahead.code != SEOF_T)
{
lookahead = malar_next_token(sc_buf);
}
return;
}
}
if (pr_token_code != SEOF_T)
exit(synerrno);
}
/* Outputs an error message to stdout using the current lookahead token
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: printf, b_setmark
* Parameters: N/A
*/
void syn_printe()
{
printf("PLATY: Syntax error: Line:%3d\n***** Token code: %3d Attribute: ", line, lookahead.code);
switch (lookahead.code)
{
case ERR_T:
printf("%s\n", lookahead.attribute.err_lex);
break;
case SEOF_T:
printf("NA\n");
break;
case AVID_T:
case SVID_T:
printf("%s\n", sym_table.pstvr[lookahead.attribute.get_int].plex);
break;
case FPL_T:
printf("%5.1f\n", lookahead.attribute.flt_value);
break;
case INL_T:
printf("%d\n", lookahead.attribute.get_int);
break;
case STR_T:
printf("%s\n", b_setmark(str_LTBL, lookahead.attribute.str_offset));
break;
case SCC_OP_T:
printf("NA\n");
break;
case ASS_OP_T:
printf("NA\n");
break;
case ART_OP_T:
printf("%d\n", lookahead.attribute.get_int);
break;
case REL_OP_T:
printf("%d\n", lookahead.attribute.get_int);
break;
case LOG_OP_T:
printf("%d\n", lookahead.attribute.get_int);
break;
case LPR_T:
printf("NA\n");
break;
case RPR_T:
printf("NA\n");
break;
case LBR_T:
printf("NA\n");
break;
case RBR_T:
printf("NA\n");
break;
case KW_T:
printf("%s\n", kw_table[lookahead.attribute.get_int]);
break;
case COM_T:
printf("NA\n");
break;
case EOS_T:
printf("NA\n");
break;
default:
printf("PLATY: Scanner error: invalid token code: %d\n", lookahead.code);
}
}
/* Generates a message to stdout (can be later modified to generate C code)
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: printf
* Parameters: char* code
* Return value: N/A
*/
void gen_incode(char *code)
{
printf("%s\n", code);
}
/*
* Grammar functions ahoy
*/
/*
* <additive_arithmetic_expression> ->
<multiplicative_arithmetic_expression> <additive_arithmetic_expression_prime>
FIRST Set = {AVID_T, FPL_T, INL_T, (}
*/
void additive_arithmetic_expression()
{
multiplicative_arithmetic_expression();
additive_arithmetic_expression_prime();
}
/*
* <additive_arithmetic_expression> ->
<multiplicative_arithmetic_expression> <additive_arithmetic_expression_prime>
FIRST Set = {AVID_T, FPL_T, INL_T, (}
*/
void additive_arithmetic_expression_prime()
{
if (lookahead.code == ART_OP_T &&
lookahead.attribute.arr_op != MULT &&
lookahead.attribute.arr_op != DIV)
{
match(lookahead.code, lookahead.attribute.arr_op);
multiplicative_arithmetic_expression();
additive_arithmetic_expression_prime();
gen_incode("PLATY: Additive arithmetic expression parsed");
}
}
/*
* <opt_LPR_T> <unary_arithmetic_expression> <opt_RPR_T> |
<opt_LPR_T> <additive_arithmetic_expression> <opt_RPR_T>
FIRST Set = {-, +, AVID_T, FPL_T, INL_T, (}
*/
void arithmetic_expression()
{
/* GCC complains that PLUS and MINUS enums aren't handled,
but this is automatically handled in additive_arithmetic_expression()
*/
switch (lookahead.code)
{
case ART_OP_T:
switch (lookahead.attribute.arr_op)
{
case MULT:
case DIV:
syn_printe();
return;
}
unary_arithmetic_expression();
break;
case AVID_T:
case FPL_T:
case INL_T:
case LPR_T:
additive_arithmetic_expression();
break;
case EOS_T:
return;
default:
syn_printe();
return;
}
gen_incode("PLATY: Arithmetic expression parsed");
}
/*
* <assignment_expression> ->
AVID = <arithmetic_expression> | SVID = <string_expression>
FIRST Set = {AVID, SVID}
*/
void assignment_expression()
{
switch (lookahead.code)
{
case AVID_T:
match(AVID_T, NO_ATTR);
match(ASS_OP_T, NO_ATTR);
arithmetic_expression();
gen_incode("PLATY: Assignment expression (arithmetic) parsed");
break;
case SVID_T:
match(SVID_T, NO_ATTR);
match(ASS_OP_T, NO_ATTR);
string_expression();
gen_incode("PLATY: Assignment expression (string) parsed");
break;
default:
syn_printe();
}
}
/*
* <assignment_statement> ->
<assignment_expression> ;
FIRST Set = {AVID, SVID}
*/
void assignment_statement()
{
assignment_expression();
match(EOS_T, NO_ATTR);
gen_incode("PLATY: Assignment statement parsed");
}
/*
* <conditional_expression> ->
<logical_or_expression>
FIRST Set = {AVID_T, SVID_T, INL_T, SVID_T, STR_T}
*/
void conditional_expression()
{
logical_or_expression();
gen_incode("PLATY: Conditional expression parsed");
}
/*
* <input_statement> ->
INPUT ( <variable_list> );
FIRST Set = {INPUT}
*/
void input_statement()
{
match(KW_T, INPUT);
match(LPR_T, NO_ATTR);
variable_list();
match(RPR_T, NO_ATTR);
match(EOS_T, NO_ATTR);
gen_incode("PLATY: Input statement parsed");
}
/*
* <iteration_statement> ->
USING ( <assignment_expression>, <conditional_expression>, <assignment_expression> ) REPEAT { <opt_statements> } ;
FIRST Set = {USING}
*/
void iteration_statement()
{
match(KW_T, USING);
match(LPR_T, NO_ATTR);
assignment_expression();
match(COM_T, NO_ATTR);
assignment_expression();
match(RPR_T, NO_ATTR);
match(KW_T, REPEAT);
match(LBR_T, NO_ATTR);
opt_statements();
match(RBR_T, NO_ATTR);
match(EOS_T, NO_ATTR);
gen_incode("PLATY: USING statement parsed");
}
/*
* <logical_and_expression> ->
<relational_expression> <logical_and_expression_prime>
FIRST Set = {AVID_T, FPL_T, INL_T, SVID_T, STR_T}
*/
void logical_and_expression()
{
relational_expression();
logical_and_expression_prime();
}
/*
* <logical_and_expression_prime> ->
.AND. <relational_expression> <logical_and_expression_prime> | E
FIRST Set = { .AND., E}
*/
void logical_and_expression_prime()
{
if (lookahead.code == LOG_OP_T &&
lookahead.attribute.log_op == AND)
{
match(LOG_OP_T, AND);
relational_expression();
logical_and_expression_prime();
gen_incode("PLATY: Logical AND expression parsed");
}
}
/*
* <logical_or_expression> ->
<logical_and_expression> <logical_or_expression_prime>
FIRST Set = {AVID_T, FPL_T, INL_T, SVID_T, STR_T}
*/
void logical_or_expression()
{
logical_and_expression();
logical_or_expression_prime();
}
/*
* <logical_or_expression_prime> ->
.OR. <logical_and_expression> <logical_or_expression_prime>
FIRST Set = { .OR., E }
*/
void logical_or_expression_prime()
{
if (lookahead.code == LOG_OP_T &&
lookahead.attribute.log_op == OR)
{
logical_and_expression();
logical_or_expression_prime();
gen_incode("PLATY: Logical OR expression parsed");
}
}
/*
* <multiplicative_arithmetic_expression> ->
<primary_arithmetic_expression> <multiplicative_arithmetic_expression_prime>
FIRST Set = {AVID_T, FPL_T, INL_T, (}
*/
void multiplicative_arithmetic_expression()
{
primary_arithmetic_expression();
multiplicative_arithmetic_expression_prime();
}
/*
* <multiplicative_arithmetic_expression_prime> ->
<primary_arithmetic_expression> <multiplicative_arithmetic_expression_prime>
FIRST Set = {*, /, E}
*/
void multiplicative_arithmetic_expression_prime()
{
if (lookahead.code == ART_OP_T &&
lookahead.attribute.arr_op != PLUS &&
lookahead.attribute.arr_op != MINUS)
{
match(lookahead.code, lookahead.attribute.arr_op);
primary_arithmetic_expression();
multiplicative_arithmetic_expression_prime();
gen_incode("PLATY: Multiplicative arithmetic expression parsed");
}
}
/*
* <opt_statements> ->
<statements> | E
FIRST Set = {AVID_T, SVID_T, IF, USING, INPUT, OUTPUT, E}
*/
void opt_statements()
{
switch (lookahead.code)
{
case KW_T:
switch (lookahead.attribute.kwt_idx)
{
case PLATYPUS:
case ELSE:
case THEN:
case REPEAT:
gen_incode("PLATY: Opt_statements parsed");
return;
}
case AVID_T:
case SVID_T:
statements();
break;
default:
gen_incode("PLATY: Opt_statements parsed");
}
}
/*
* <output_statement> ->
OUTPUT ( <output_statement_prime> );
<output_statement_prime> ->
<variable_list> | <STR_T>
FIRST(<output_statement>) = {OUTPUT}
FIRST Set = {AVID_T, SVID_T, E}
This can be done in one function
*/
void output_statement()
{
match(KW_T, OUTPUT);
match(LPR_T, NO_ATTR);
switch (lookahead.code)
{
case AVID_T:
case SVID_T:
variable_list();
break;
case STR_T:
match(STR_T, NO_ATTR);
gen_incode("PLATY: Output list (string literal) parsed");
break;
default:
gen_incode("PLATY: Output list (empty) parsed");
}
match(RPR_T, NO_ATTR);
match(EOS_T, NO_ATTR);
gen_incode("PLATY: OUTPUT statement parsed");
}
/*
* <primary_a_relational_expression> ->
AVID_T | FPL_T | INL_T
FIRST Set = {AVID_T, FPL_T, INL_T}
*/
void primary_a_relational_expression()
{
switch (lookahead.code)
{
case AVID_T:
case FPL_T:
case INL_T:
match(lookahead.code, NO_ATTR);
break;
case LOG_OP_T:
break;
default:
syn_printe();
}
gen_incode("PLATY: Primary a_relational expression parsed");
}
/*
* <primary_arithmetic_expression> ->
AVID_T | FPL_T | INL_T | ( <arithmetic_expression> )
FIRST Set = {AVID_T, FPL_T, INL_T, (}
*/
void primary_arithmetic_expression()
{
switch (lookahead.code)
{
case AVID_T:
case FPL_T:
case INL_T:
match(lookahead.code, lookahead.attribute.arr_op);
break;
case LPR_T:
match(lookahead.code, lookahead.attribute.arr_op);
arithmetic_expression();
match(RPR_T, NO_ATTR);
default:
syn_printe();
return;
}
gen_incode("PLATY: Primary arithmetic expression parsed");
}
/*
* <primary_s_relational_expression> ->
<primary_string_expression>
FIRST Set = {SVID_T, STR_T}
*/
void primary_s_relational_expression()
{
switch (lookahead.code)
{
case SVID_T:
case AVID_T:
primary_string_expression();
break;
default:
syn_printe();
}
gen_incode("PLATY: Primary s_relational expression parsed");
}
/*
* <primary_string_expression> ->
SVID_T | STR_T
FIRST Set = {SVID_T, STR_T}
*/
void primary_string_expression()
{
switch (lookahead.code)
{
case SVID_T:
case STR_T:
match(lookahead.code, NO_ATTR);
break;
default:
syn_printe();
}
gen_incode("PLATY: Primary string expression parsed");
}
/*
* <program> ->
PLATYPUS { <opt_statements> }
FIRST Set = {PLATYPUS}
*/
void program()
{
match(KW_T, PLATYPUS);
match(LBR_T, NO_ATTR);
opt_statements();
match(RBR_T, NO_ATTR);
gen_incode("PLATY: Program parsed");
}
/*
* <relational_expression> ->
<primary_a_relational_expression> <primary_a_relational_expression>
| <primary_s_relational_expression> <primary_s_relational_expression_prime>
FIRST Set = {AVID_T, FPL_T, INL_T, SVID_T, STR_T}
*/
void relational_expression()
{
switch (lookahead.code)
{
case AVID_T:
case FPL_T:
case INL_T:
primary_a_relational_expression();
relational_expression_prime();
break;
case SVID_T:
case STR_T:
primary_s_relational_expression();
relational_expression_prime_string();
break;
default:
syn_printe();
}
gen_incode("PLATY: Relational expression parsed");
}
/*
* <relational_expression_prime> ->
== <primary_a_relational_expression>
| <> <primary_a_relational_expression>
| > <primary_a_relational_expression>
| < <primary_a_relational_expression>
FIRST Set = { ==, <>, >, <}
*/
void relational_expression_prime()
{
if (lookahead.code == REL_OP_T)
{
switch (lookahead.attribute.rel_op)
{
case EQ:
case NE:
case GT:
case LT:
match(lookahead.code, lookahead.attribute.arr_op);
primary_a_relational_expression();
return;
}
}
syn_printe();
}
/*
* <relational_expression_prime_string> ->
== <primary_s_relational_expression>
| <> <primary_s_relational_expression>
| > <primary_s_relational_expression>
| < <primary_s_relational_expression>
FIRST Set = {==, <>, >, <}
*/
void relational_expression_prime_string()
{
if (lookahead.code == REL_OP_T)
{
switch (lookahead.attribute.rel_op)
{
case EQ:
case NE:
case GT:
case LT:
match(lookahead.code, lookahead.attribute.arr_op);
primary_s_relational_expression();
return;
}
}
syn_printe();
}
/*
* <selection_statement> ->
IF ( <conditional_expression> ) THEN <opt_statements> ELSE { <opt_statements> } ;
FIRST Set = {IF}
*/
void selection_statement()
{
match(KW_T, IF);
match(LPR_T, NO_ATTR);
conditional_expression();
match(RPR_T, NO_ATTR);
match(KW_T, THEN);
opt_statements();
match(KW_T, ELSE);
match(LBR_T, NO_ATTR);
opt_statements();
match(RBR_T, NO_ATTR);
match(EOS_T, NO_ATTR);
gen_incode("PLATY: IF statement parsed");
}
/*
* <statement> ->
<assignment_statement>
| <selection_statement>
| <iteration_statement>
| <input_statement>
| <output_statement>
FIRST Set = {AVID_T, SVID_T, IF, USING, INPUT, OUTPUT}
*/
void statement()
{
switch (lookahead.code)
{
case AVID_T:
case SVID_T:
assignment_statement();
break;
case KW_T:
switch (lookahead.attribute.kwt_idx)
{
case IF:
selection_statement();
break;
case USING:
iteration_statement();
break;
case INPUT:
input_statement();
break;
case OUTPUT:
output_statement();
break;
default:
syn_printe();
}
break;
default:
syn_printe();
}
}
/*
* <statements> ->
<statement> <statements_prime>
FIRST Set = {AVID_T, SVID_T, IF, USING, INPUT, OUTPUT}
*/
void statements()
{
statement();
statements_prime();
}
/*
* <statements_prime> ->
<statement> <statements_prime> | E
FIRST Set = {AVID_T, SVID_T, IF, USING, INPUT, OUTPUT}
*/
void statements_prime()
{
switch (lookahead.code)
{
case KW_T:
switch (lookahead.attribute.kwt_idx)
{
case PLATYPUS:
case ELSE:
case THEN:
case REPEAT:
return;
}
case AVID_T:
case SVID_T:
statement();
statements_prime();
break;
}
}
/*
* <string_expression> ->
<primary_string_expression> <string_expression_prime>
FIRST Set = {SVID_T, STR_T}
*/
void string_expression()
{
primary_string_expression();
string_expression_prime();
gen_incode("PLATY: String expression parsed");
}
/*
* <string_expression_prime>
<< <primary_string_expression> <stirng_expression_prime> | E
FIRST Set = {<< , E}
*/
void string_expression_prime()
{
if (lookahead.code == SCC_OP_T)
{
match(SCC_OP_T, NO_ATTR);
primary_string_expression();
string_expression_prime();
}
}
/*
* <unary_arithmetic_expression> ->
- <primary_arithmetic_expression>
| + <primary_arithmetic_expression>
FIRST Set = {-, +}
*/
void unary_arithmetic_expression()
{
/* Again, GCC complains about PLUS and MINUS enums */
switch (lookahead.code)
{
case ART_OP_T:
switch (lookahead.attribute.arr_op)
{
case MULT:
case DIV:
syn_printe();
return;
}
match(lookahead.code, lookahead.attribute.arr_op);
primary_arithmetic_expression();
gen_incode("PLATY: Unary arithmetic expression parsed");
break;
default:
syn_printe();
return;
}
}
/*
* <variable_identifier> ->
AVID_T | SVID_T
FIRST Set = {AVID_T, SVID_T}
*/
void variable_identifier()
{
switch (lookahead.code)
{
case AVID_T:
case SVID_T:
match(lookahead.code, NO_ATTR);
break;
default:
syn_printe();
}
}
/*
* <variable_list> ->
<variable_identifier> <variable_list_prime>
FIRST Set = {AVID_T, SVID_T}
*/
void variable_list()
{
variable_identifier();
variable_list_prime();
gen_incode("PLATY: Variable list parsed");
}
/*
* <variable_list_prime> ->
, <variable_identifier> <variable_list_prime> | E
FIRST Set = {AVID_T, SVID_T, E}
*/
void variable_list_prime()
{
if (lookahead.code != COM_T)
return;
match(COM_T, NO_ATTR);
variable_identifier();
variable_list_prime();
}