int initsyn() { syms1=newsymbol(""); syms2=newsymbol(""); syms3=newsymbol(""); tempo=searchsym("tempo"); hz=searchsym("Hz"); }
// Function to get the value of a given symbol in the symbol table. Value getsym_id (char *name){ symrec *sym; // Search for the symbol in the symbol table. sym = searchsym(name); // If the symbol doesn't exist ... if(sym == NULL){ // ... Throw an error and exit. printf("Variable %s not declared before \n", name); exit(1); } // Check if the symbol is a function. if(sym->type == sym_func){ printf("Symbol %s is a function, not a variable\n", name); exit(1); } // Return the value of the symbol. return sym->value; }
// Function to add a symbol to the symbol table of a given name. symrec *putsym(char *name, symEnum type, struct nodeTypeTag *func_tree){ // First, search if the symbol exists. symrec *sym = searchsym(name); // if the symbol already exists ... if(sym != NULL){ // ... Don't do anything, and throw an error. printf("Symbol already exists!\n"); return NULL; } // Create a place in the memory for the symbol. sym = (symrec *)malloc(sizeof(symrec)); if(sym == NULL){ printf("Not enough memory!\n"); exit (-1); } // Create enough place for the name of the symbol. sym->name = (char *)malloc(sizeof(strlen(name)+1)); if(sym->name == NULL){ printf("Not enough memory for name!\n"); exit (-1); } // Set the name of the symbol. sym->name = name; // Set the type of the symbol (Id, function). sym->type = type; // If the symbol is a function, add it's body to it. if (type == sym_func){ sym->func_tree = func_tree; } // Add the symbol to the start of the symbol table. sym->next = sym_node; // Point at the symbol, making it the first symbol in the table. sym_node = sym; return sym; }
// Function to change the value of a given symbol in the symbol table to a given Value and returns the new value. Value symchange_id(char *name, Value newValue){ symrec *sym; // Search for the symbol in the symbol table. sym = searchsym(name); // If the symbol doesn't exist ... if(sym == NULL){ // ... throw an error and exist. printf("No variable found with name %s\n",name); exit (-1); } // Check if the symbol is a function. if(sym->type == sym_func){ printf("Symbol %s is a function, not a variable\n", name); exit(1); } // Change the value of the found symbol. sym->value = newValue; // Return the value of the symbol. return sym->value; }
int syntaxan (int token,symbol * sym) { static unsigned char num_channel; static unsigned char channels[12]={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static symbol ptr; switch (status) { case STATUS_INIT: /* Initial status */ recst = STATUS_INIT; /*Save actual state for error handling */ switch (token) { case VAR: /* Begin variable declaration */ status = STATUS_BEGIN_VAR_DECL; return 0; case CHANNEL: /* Begin channel declaration */ status = STATUS_BEGIN_CHN_DECL; return 0; case IDEN: /* Begin assign statement */ status = STATUS_BEGIN_GLOBAL_ASGN; /* TODO: Join to local assign */ if ((*sym = searchsym(lexcad)) == NULL) rerror(ESYNTAX, EIDEN_NAME, 0); return 0; case LN: /* Empty sentence */ return 1; default: rerror(ESYNTAX, E_INI, 0); } /* Variable declaration states */ case STATUS_BEGIN_VAR_DECL: /* VAR ; variable declaration */ switch (token) { case IDEN: /* Name of the variable */ status = STATUS_NAME_VAR_DECL; *sym = newsymbol(lexcad); return 0; default: rerror(ESYNTAX, E_VAR_DECL, 0); } case STATUS_NAME_VAR_DECL: /* VAR IDEN ; variable declaration */ switch (token) { case LN: /* end of declaration */ status = STATUS_INIT; insvar(*sym); return 1; case COMA: /* multiple declaration */ status = STATUS_BEGIN_VAR_DECL; insvar(*sym); return 0; default: rerror(ESYNTAX, E_VAR_DECL, 0); } /* Channel declaration states */ case STATUS_BEGIN_CHN_DECL: /* CHANNEL ; channel declaration */ switch (token) { case NUMBER: /* Number of the channel */ status = STATUS_END_OF_CHANNEL; num_channel = atoi(lexcad) - 1; if(num_channel >= 12) rerror(ESYNTAX, E_BAD_CH, 0); else { ssymval(syms1, num_channel); *sym = syms1; } if(channels[num_channel]) rerror(ESYNTAX, E_DECL_CH, 0); channels[num_channel]=1; return 0; case IDEN: /* Variable with the name of the channel */ status = STATUS_END_OF_CHANNEL; if ((*sym = searchsym(lexcad)) == NULL) rerror(ESYNTAX, EIDEN_NAME, 0); else if ((num_channel = gsymval(*sym)) >= 12) rerror(ESYNTAX, E_BAD_CH, 0); if (channels[num_channel]) rerror(ESYNTAX, E_DECL_CH, 0); channels[num_channel] = 1; return 0; default: rerror(ESYNTAX, E_CHANNEL, 0); } /* end of channel declaration */ case STATUS_END_OF_CHANNEL: /* CHANNEL IDEN | NUMBER ; end of channl dcl*/ switch (token) { case LN: /* finish channel dcl */ status = STATUS_BEGIN_CHN_BODY; inscode2(CHANNEL, gsymval(*sym)); return 1; default: rerror(ESYNTAX, E_CHANNEL, 0); } /* Begin channel body */ case STATUS_BEGIN_CHN_BODY: /* CHANNEL IDEN | NUMBER LN ; chl body*/ recst = STATUS_BEGIN_CHN_BODY; /*Save state for error handling*/ switch (token) { case LN: return 1; case ENDC: /* end of channel statement */ status = STATUS_BEGIN_ENDC; initsym(syms1, token, token); *sym = syms1; return 0; case PLAY: status = 11; /* play statement */ initexpr(); initsym(syms1, token, token); *sym = syms1; return 0; case SIL: /* silence statement */ case DECOC: /* dec octave statement */ case INCOC: /* inc octave statement */ case ENDL: /* end of loop statement */ case DECV: /* dec volume */ case INCV: /* inc volume */ status = STATUS_END_OF_1CMD; initsym(syms1, token, token); *sym = syms1; return 0; case OCT: /* octave statement */ case VOL: /* volume statement */ case BAT: /* battery statement */ case INST: /* instrument statement */ case LOOP: /* loop statement */ case AMPL: case VIB: /* vibrato statement */ case TIMES: /* time short format statement */ case TIMEL: /* time long format statement */ case DIVSUS: case BATL: /* battery long format statement */ case INSTL: /* instrument long format statement */ case FREC: /* set frequency statement */ status = STATUS_BEGIN_EXP_2CMD; initexpr(); initsym(syms1, token, token); *sym = syms1; return 0; case TIMEP: status = 39; initexpr(); initsym(syms1, token, token); initsym(syms2, NUMBER, 0); ssymsig(syms2, syms1); *sym = syms2; return 0; case REGFM: /* write to fm register statement */ status = 8; initexpr(); initsym(syms1, token, token); *sym = syms1; return 0; case PAR: /* parameter statement */ status = 9; initsym(syms1, token, token); *sym = syms1; return 0; case IDEN: /* Begin a assign statement */ status = 10; if ((*sym = searchsym(lexcad)) == NULL) rerror(ESYNTAX, EIDEN_NAME, 0); return 0; default: rerror(ESYNTAX, E_UNK_COMM, 0); } /* End of 1 word statement */ case STATUS_END_OF_1CMD: switch (token) { case LN: status = STATUS_BEGIN_CHN_BODY; inscodeI(*sym, NULL, num_channel); return 1; default: rerror(ESYNTAX, E_BAD_COMM, 0); } case 8: switch (token) { case NUMBER: status = 21; initsym(syms3, NUMBER, 0); ssymsig(syms3,*sym); *sym = syms3; pushexp(NUMBER, atoi(lexcad)); return 0; case IDEN: status = 21; if((ptr = searchsym(lexcad)) == NULL) rerror(ESYNTAX, EIDEN_NAME, 0); initsym(syms3, NUMBER, 0); ssymsig(syms3,*sym); *sym = syms3; pushexp(NUMBER, gsymval(ptr)); return 0; case PARI: status = 22; ssymsig(syms3,*sym); *sym = syms3; pushexp(token, 0); return 0; default: rerror(ESYNTAX, E_EXP, 0); } case 9: switch (token) { case ENVLOFF: case ENVLON: case SUSON: case HFNUM: case LFNUM: case NOISE: case TONE: status = STATUS_END_OF_1CMD; initsym(syms2, token, token); ssymsig(syms2,*sym); *sym = syms2; return 0; case DECO: status = STATUS_BEGIN_EXP_2CMD; initexpr(); initsym(syms3, token, token); ssymsig(syms3,*sym); *sym = syms3; return 0; case TAMP: status = STATUS_BEGIN_EXP_2CMD; initexpr(); initsym(syms3, token, token); ssymsig(syms3,*sym); *sym = syms3; return 0; case RITMON: status = STATUS_END_OF_1CMD; initsym(syms2, token, token); ssymsig(syms2,*sym); *sym = syms2; return 0; case MELON: status = STATUS_END_OF_1CMD; initsym(syms2, token, token); ssymsig(syms2,*sym); *sym = syms2; return 0; default: rerror(ESYNTAX, E_PAR, 0); } case 10: switch (token) { case EQ: status = STATUS_BEGIN_EXP_2CMD; initexpr(); initsym(syms3, EQ, EQ); ssymsig(syms3, *sym); *sym = syms3; return 0; default: rerror(ESYNTAX, E_ASIG, 0); } case 11: switch(token) { case NUMBER: status = STATUS_PLAY_EXPRESION; initsym(syms2, NUMBER, 0); ssymsig(syms2,*sym); *sym = syms2; pushexp(NUMBER, atoi(lexcad)); return 0; case IDEN: status = STATUS_PLAY_EXPRESION; if((ptr = searchsym(lexcad)) == NULL) rerror(ESYNTAX, EIDEN_NAME, 0); initsym(syms2, NUMBER, 0); ssymsig(syms2,*sym); *sym = syms2; pushexp(NUMBER, gsymval(ptr)); return 0; case PARI: status = STATUS_PLAY_EXPRESION; ssymsig(syms2,*sym); *sym = syms2; pushexp(token, 0); return 0; default: rerror(ESYNTAX, E_EXP, 0); } /* Begin end of channel statement */ case STATUS_BEGIN_ENDC: /* ENDC ; endc command */ switch(token) { case LN: status = 13; inscode(gsymval(*sym)); execute(); return 1; default: rerror(ESYNTAX, E_BAD_COMM, 0); } case 13: recst = 13; switch(token) { case WRITE: status = 38; return 0; case CHANNEL: status = STATUS_BEGIN_CHN_DECL; return 0; case LN: return 1; default: rerror(ESYNTAX, E_INI, 0); } case STATUS_BEGIN_GLOBAL_ASGN: switch(token) { case EQ: status = 15; initexpr(); return 0; default: rerror(ESYNTAX, E_ASIG, 0); } case 15: switch(token) { case NUMBER: status = 26; {pushexp(NUMBER, atoi(lexcad));}; return 0; case IDEN: status = 26; (ptr = searchsym(lexcad))?pushexp(NUMBER, gsymval(ptr)):rerror(ESYNTAX, EIDEN_NAME, 0); return 0; case PARI: status = 27; pushexp(token, 0); return 0; default: rerror(ESYNTAX, E_EXP, 0); } /*******************************************************************/ case STATUS_BEGIN_EXP_2CMD: switch (token) { case PARI: status = STATUS_EXP2_OPERAND; ssymsig(syms2,*sym); *sym = syms2; pushexp(token, 0); return 0; case NUMBER: status = STATUS_EXP2_OPERAND; initsym(syms2, NUMBER, 0); ssymsig(syms2,*sym); *sym = syms2; pushexp(NUMBER, atoi(lexcad)); return 0; case IDEN: status = STATUS_EXP2_OPERAND; if(!(ptr = searchsym(lexcad))) rerror(ESYNTAX, EIDEN_NAME, 0); initsym(syms2, NUMBER, 0); ssymsig(syms2,*sym); *sym = syms2; pushexp(NUMBER, gsymval(ptr)); return 0; default: rerror(ESYNTAX, E_EXP, 0); } case STATUS_EXP2_OPERAND: switch(token) { case NUMBER: status = STATUS_EXP2_OPERAND; pushexp(NUMBER, atoi(lexcad)); return 0; case IDEN: status = STATUS_EXP2_OPERAND; if ((ptr = searchsym(lexcad)) == NULL) rerror(ESYNTAX, EIDEN_NAME, 0); pushexp(NUMBER, gsymval(ptr)); return 0; case ADD: case SUB: case MUL: case DIV: case PARD: case PARI: /* left parenthesis */ status = STATUS_EXP2_OPERAND; pushexp(token, 0); return 0; case LN: status = recst; pushexp(token, 0); ssymval(*sym, evalexpr()); inscodeI(*sym, NULL, num_channel); return 1; default: rerror(ESYNTAX, E_EXP, 0); } /***********************************************/ /* initial assign expression*/ case 26: switch(token) { case ADD: status = 15; pushexp(token, 0); return 0; case SUB: status = 15; pushexp(token, 0); return 0; case MUL: status = 15; pushexp(token, 0); return 0; case DIV: status = 15; pushexp(token, 0); return 0; case LN: status = STATUS_INIT;{pushexp(token, 0);ssymval(*sym, evalexpr());} return 1; default: rerror(ESYNTAX, E_EXP, 0); } case 27: switch(token) { case NUMBER: status = 28;{pushexp(NUMBER, atoi(lexcad));}return 0; case IDEN: status = 28;{symbol ptr;(ptr = searchsym(lexcad))?pushexp(NUMBER, gsymval(ptr)):rerror(ESYNTAX, EIDEN_NAME, 0);}return 0; case PARI: status = 27; pushexp(token, 0); return 0; default: rerror(ESYNTAX, E_EXP, 0); } case 28: switch(token) { case PARD: status = 28; pushexp(token, 0); return 0; case ADD: status = 27; pushexp(token, 0); return 0; case SUB: status = 27; pushexp(token, 0); return 0; case MUL: status = 27; pushexp(token, 0); return 0; case DIV: status = 27; pushexp(token, 0); return 0; case LN: status = STATUS_INIT;{pushexp(token, 0);ssymval(*sym, evalexpr());}return 1; default: rerror(ESYNTAX, E_EXP, 0); } case 30: /*Expresion de play*/ case STATUS_PLAY_EXPRESION: switch(token) { case ADD: case SUB: case MUL: case DIV: status = 32; pushexp(token, 0); return 0; case SOS: status = STATUS_PLAY_SOST; return 0; case BEMOL: status = STATUS_PLAY_BEMOL; return 0; case COMA: case LN: pushexp(LN, 0); ssymval(*sym, evalexpr()); inscodeI(*sym, NULL, num_channel); if (token == COMA) { status = 32; initexpr(); return 0; } else { status = STATUS_BEGIN_CHN_BODY; return 1; } default: rerror(ESYNTAX, E_EXP, 0); } case 32: switch(token) { case NUMBER: status = 33;{pushexp(NUMBER, atoi(lexcad));}return 0; case IDEN: status = 33;{symbol ptr;(ptr = searchsym(lexcad))?pushexp(NUMBER, gsymval(ptr)):rerror(ESYNTAX, EIDEN_NAME, 0);}return 0; case PARI: status = 32; pushexp(token, 0); return 0; default: rerror(ESYNTAX, E_EXP, 0); } case 33: switch(token) { case PARD: status = 33; pushexp(token, 0); return 0; case ADD: status = 34; pushexp(token, 0); return 0; case SUB: status = 34; pushexp(token, 0); return 0; case MUL: status = 34; pushexp(token, 0); return 0; case DIV: status = 34; pushexp(token, 0); return 0; case SOS: status = STATUS_PLAY_SOST;{pushexp(token, 0);ssymval(*sym, evalexpr());}return 0; case BEMOL: status = STATUS_PLAY_BEMOL;{pushexp(token, 0);ssymval(*sym, evalexpr());}return 0; case COMA: status = 32;{pushexp(LN, 0);ssymval(*sym, evalexpr());inscodeI(*sym, NULL, num_channel);initexpr();} return 0; case LN: status = STATUS_BEGIN_CHN_BODY;{pushexp(token, 0);ssymval(*sym, evalexpr());inscodeI(*sym, NULL, num_channel);}return 1; default: rerror(ESYNTAX, E_EXP, 0); } case 34: switch(token) { case NUMBER: status = STATUS_PLAY_EXPRESION;{pushexp(NUMBER, atoi(lexcad));}return 0; case IDEN: status = STATUS_PLAY_EXPRESION;{symbol ptr;(ptr = searchsym(lexcad))?pushexp(NUMBER, gsymval(ptr)):rerror(ESYNTAX, EIDEN_NAME, 0);}return 0; case PARI: status = 32; pushexp(token, 0); return 0; default: rerror(ESYNTAX, E_EXP, 0); } case STATUS_PLAY_BEMOL: switch(token) { case BEMOL: pushexp(SUB, 0); pushexp(NUMBER, 3); return 0; case COMA: case LN: pushexp(LN, 0); ssymval(*sym, evalexpr() - 3); inscodeI(*sym, NULL, num_channel); if (token == LN) { status = STATUS_BEGIN_CHN_BODY; return 1; } else { status = 32; initexpr(); return 0; } default: rerror(ESYNTAX, E_BEMOL, 0); } case STATUS_PLAY_SOST: switch(token) { case SOS: pushexp(ADD, 0); pushexp(NUMBER, 3); return 0; case COMA: case LN: pushexp(LN, 0); ssymval(*sym, evalexpr() + 3); inscodeI(*sym, NULL, num_channel); if (token == LN) { status = STATUS_BEGIN_CHN_BODY; return 1; } else { status = 32; initexpr(); return 0; } default: rerror(ESYNTAX, E_SOS, 0); } case 38: switch(token) { case LN: status = 37;{errorg?rerror(EERROR, 0, 0):writesong();}return 2; /*Fin de entrada*/ default: rerror(ESYNTAX, E_BAD_COMM, 0); } case 39: switch (token) { case NUMBER: status = 40;{pushexp(NUMBER, atoi(lexcad));}return 0; case IDEN: status = 40;{symbol ptr;(ptr = searchsym(lexcad))?pushexp(NUMBER, gsymval(ptr)):rerror(ESYNTAX, EIDEN_NAME, 0);}return 0; case PARI: status = 41; pushexp(token, 0); return 0; default: rerror(ESYNTAX, E_EXP, 0); } case 40: switch(token) { case ADD: status = 39; pushexp(token, 0); return 0; case SUB: status = 39; pushexp(token, 0); return 0; case MUL: status = 39; pushexp(token, 0); return 0; case DIV: status = 39; pushexp(token, 0); return 0; case POINT: status = 43;{pointp = point=32;}; return 0; case LN: status = STATUS_BEGIN_CHN_BODY; { float time; pushexp(token, 0); time = evalexpr(); time/=64.0; time*=(240.0*((float)(gsymval(hz))))/((float)(gsymval(tempo))); if((time-((float)((unsigned char)time))) > 0.5) time=((float)((unsigned char)time))+1.0; else time=(float)((unsigned char)time); ssymval(*sym,(unsigned char)time); inscodeI(*sym, NULL, num_channel); }return 1; default: rerror(ESYNTAX, E_EXP, 0); } case 41: switch(token) { case NUMBER: status = 42;{pushexp(NUMBER, atoi(lexcad));}return 0; case IDEN: status = 42;{symbol ptr;(ptr = searchsym(lexcad))?pushexp(NUMBER, gsymval(ptr)):rerror(ESYNTAX, EIDEN_NAME, 0);}return 0; case PARI: status = 41; pushexp(token, 0); return 0; default: rerror(ESYNTAX, E_EXP, 0); } case 42: switch(token) { case PARD: status = 42; pushexp(token, 0); return 0; case ADD: case SUB: case MUL: case DIV: status = 41; pushexp(token, 0); return 0; case POINT: status = 43;{pointp = point=32;} return 0; case LN: status = STATUS_BEGIN_CHN_BODY; { float time, timei; pushexp(token, 0); time = evalexpr(); time/=64.0; time*=(240.0*((float)(gsymval(hz))))/((float)(gsymval(tempo))); time = fabs(time); timei = floor(time); if(time-timei) time = timei+1.0; else time = timei; ssymval(*sym,(unsigned char)time); inscodeI(*sym, NULL, num_channel); }return 1; default: rerror(ESYNTAX, E_EXP, 0); } case 43: switch(token) { case POINT: pointp >>= 1; point += pointp; return 0; case LN: status = STATUS_BEGIN_CHN_BODY; { float time, timei; pushexp(token, 0); time = evalexpr(); time/=64; time*=(240.0*((float)(gsymval(hz))))/((float)(gsymval(tempo))); time = fabs(time); time+=time*(((float)point)/64.0); timei = floor(time); if(time-timei) time = timei+1.0; else time = timei; ssymval(*sym,(unsigned char)time); inscodeI(*sym, NULL, num_channel); }return 1; } default: rerror(ESYNTAX, E_POINT, 0); } }
// Function to execute a node in the AST and returns the value of the executed node. Value ex(nodeType *p){ // If the node is empty, return an empty value (null). if (!p) return empty_value(); // Depending on the type of the node, do different actions. switch(p->type){ case typeCon: // If it was a constant. return p->con.val; // Return its value. case typeId: { // If it was an id (variable). Value v; v = getsym_id(p->id.name); // Get the value of the symbol in the symbol table. return v; // Return the value of hte symbol. } case typeFunc: { // If it was a function. // Value v; // v = getsym_id(p->id.name); // Get the value of the symbol in the symbol table. return ex(searchsym(p->func.name)->func_tree); // Return the value of hte symbol. } case typeOpr: // If it was an operation. // Check for the type of operation. switch(p->opr.oper){ case WHILE: { // If it was a while loop. LOOPLABEL: { // Define a start label. Value v = ex(p->opr.op[0]); // Execute the expression of the loop. // Depending on the type of the variable ... switch(v.type){ case conInt: // If the value is integer. // Check if it is true. if(v.ival){ // Execute the statements in the body of the while loop. ex(p->opr.op[1]); // Return to start label. goto LOOPLABEL; } break; case conReal: // If the value is real (float). // Check if it is true. if(v.realval){ // Execute the statements in the body of the while loop. ex(p->opr.op[1]); // Return to start label. goto LOOPLABEL; } break; default: // If it was a string then just ignore. break; } } return empty_value(); // Return an empty value (null). } case LOOP: { // If it was a loop. int end = ex(p->opr.op[0]).ival; //here we know it is for sure an integer. int i; for (i = 0; i < end; i++){ ex(p->opr.op[1]); // Execute the body of the loop statement. } return empty_value(); // Return an empty value. } case IF:{ // If it was an if statement. Value v = ex(p->opr.op[0]); // Execute the expression in the if statement. // Execute the if statement depending on the type of the value. switch(v.type){ case conInt: if (v.ival) ex(p->opr.op[1]); else if (p->opr.nops > 2) ex(p->opr.op[2]); break; case conReal: if (v.realval) ex(p->opr.op[1]); else if (p->opr.nops > 2) ex(p->opr.op[2]); break; default: break; } return empty_value(); } case PRINT:{ // If it is a print statement. Value v = ex(p->opr.op[0]); // Take the value of the expression. // Format the output depending on the type of the value. switch (v.type){ case conInt: printf("%d\n", v.ival); break; case conReal: printf("%f\n", v.realval); break; case conString: printf("%s\n", v.str); break; } return empty_value(); } case READ_INT: { // If it was a read integer statement. //TODO: IMPLEMENT This later. // Value v = getsym(p->opr.op[0]->id.name); // Value tmp; // switch (v.type) { // case conInt:{ // tmp.type = conInt; // scanf("%d", &tmp.ival); // symchange(p->opr.op[0]->id.name, tmp); // return empty_value(); // } // case conReal:{ // tmp.type = conReal; // scanf("%f", &tmp.realval); // symchange(p->opr.op[0]->id.name, tmp); // return empty_value(); // } // case conString:{ // tmp.type = conString; // scanf("\n%s", tmp.str); // symchange(p->opr.op[0]->id.name, tmp); // return empty_value(); // } // } // Define a new integer value. Value v; v.type = conInt; // Prompt the user to enter an integer value. printf("> "); scanf("%d", &v.ival); // Change the value of the id (variable) to the newly read integer value. symchange_id(p->opr.op[0]->id.name, v); return empty_value(); } case READ_REAL:{ // If it was a read real number (float) statement. // Define a new real number (float) value. Value v; v.type = conReal; // Prompt the user to enter a real number (float) value. printf("> "); scanf("%f", &v.realval); // Change the value of the id (variable) to the newly read real number (float) value. symchange_id(p->opr.op[0]->id.name, v); return empty_value(); } case READ_STR:{ // If it was a read string statement. // Define a new string value. Value v; v.type = conString; // Prompt the user to enter a string value printf("> "); scanf("\n%s", str_buf); // Point at the string buffer. v.str = str_buf; // Change the value of the id (variable) to the newly read string value. symchange_id(p->opr.op[0]->id.name, v); return empty_value(); } case ';': // If it was a semicolon. // Execute the operations. ex(p->opr.op[0]); return ex(p->opr.op[1]); case '=':{ // If it was an assignment statement. // Change the value of the variable to the right expression. return symchange_id(p->opr.op[0]->id.name, ex(p->opr.op[1])); } case UMINUS: { // If it was the unary minus (negative) operator. Value v = ex(p->opr.op[0]); // Get the value of the expression to be negated. // Negate the value depening on its type. switch (v.type) { case conInt: v.ival = -v.ival; break; case conReal: v.realval = -v.realval; break; default: // TODO: Reverse string when negated. return empty_value(); } return v; } // The rest are arithmetic function. They all call the ex_arith function to get executed. case '+': return ex_arith('+',ex(p->opr.op[0]),ex(p->opr.op[1])); case '-': return ex_arith('-',ex(p->opr.op[0]),ex(p->opr.op[1])); case '*': return ex_arith('*',ex(p->opr.op[0]),ex(p->opr.op[1])); case '/': return ex_arith('/',ex(p->opr.op[0]),ex(p->opr.op[1])); case '^': return ex_arith('^',ex(p->opr.op[0]),ex(p->opr.op[1])); case MOD: return ex_arith(MOD ,ex(p->opr.op[0]),ex(p->opr.op[1])); case LT: return ex_arith(LT ,ex(p->opr.op[0]),ex(p->opr.op[1])); case GT: return ex_arith(GT ,ex(p->opr.op[0]),ex(p->opr.op[1])); case LTE: return ex_arith(LTE ,ex(p->opr.op[0]),ex(p->opr.op[1])); case GTE: return ex_arith(GTE ,ex(p->opr.op[0]),ex(p->opr.op[1])); case EQ: return ex_arith(EQ ,ex(p->opr.op[0]),ex(p->opr.op[1])); case NEQ: return ex_arith(NEQ ,ex(p->opr.op[0]),ex(p->opr.op[1])); } } return empty_value(); }