/** Warning: Unless you are familliar with both parse theory and LL(1) ** top-down parsing algorithms, it's probably a very BAD idea to change ** anything here ... or even to READ it. :-) ** Just send a String* to parse_string() and get the value it returns. ** if it returns a NULL pointer, check the parse_fail_msg to see why it ** failed. Both are available externally through parser.h ** if you want to know WHY i did parsing by hand instead of YACC .. read ** the WHY file. **/ #include "parser.h" #pragma implementation #define GET_TOKEN {yylval->release(); \ yylval=NULL; \ inc = yylex();} #define VERIFY1(a) if (!(a)) return NULL; #define VERIFY2(a, b) if (!(a)) {delete b; return NULL;} #define VERIFY3(a,b,c) if (!(a)) {delete b; delete c; return NULL;} String parse_fail_msg; String* parsestring; int parse_pointer; static int inc; /** local functions **/ Value* parse_val_expr(void); Value* parse_fexpr(void); Value* parse_frest(void); Value* parse_listexpr(Value_Type l_or_ex); Val_List* parse_listrest(void); Value* parse_const(void); Value* parse_user_def(void); Val_List* parse_exprlist(void); Val_List* parse_symlist(void); Val_List* parse_symrest(void); Value* parse_coloned(void); Value* raise_parse_error(const char* msg){ char numstr[10]; parse_fail_msg = msg; parse_fail_msg += ", line "; sprintf (numstr, "%d", lex_line); parse_fail_msg += numstr; while (inc) GET_TOKEN; return (Value*)NULL; } #define PERROR(a) {raise_parse_error(a); return NULL;} Value* parse_string (String* instring){ Value* retval; static int lex_init_yet = 0; start_lex (); parsestring = instring; parse_pointer = 0; parse_fail_msg = ""; if (!lex_init_yet) {lex_init_yet = 1; lexinit();} yylval = NULL; GET_TOKEN; retval = parse_val_expr(); if (inc) {delete retval; PERROR ("GARBAGE FOUND AFTER END OF VALUE");} parsestring = NULL; return retval; } Value* parse_val_expr(){ switch (inc) {case L_PARENS: case RESERVED: return parse_fexpr(); case NUM: case REAL: case STR: case OBJ: case APOSTROPHE: case SYM: case L_BRACKET: case ERR: return parse_const(); case MTHD: PERROR ("ILLEGAL USE OF RESERVED FORM: 'method'"); case OBJ_COLON: case SYM_COLON: PERROR ("INVALID MESSAGE CALL"); case R_PARENS: case 0: PERROR ("UNEXPECTED END OF EXPRESSION"); case R_BRACKET: PERROR ("CLOSING BRACKET } FOUND WITH NO CORRESPONDING OPEN"); default: PERROR ("UNEXPECTED TOKEN: parse_val_expr()");} } Value* parse_fexpr(){ Value *temp1; switch (inc) {case L_PARENS: GET_TOKEN; return parse_frest(); case OBJ_COLON: case SYM_COLON: return parse_coloned(); case RESERVED: case SYM: temp1 = yylval->grab(); GET_TOKEN; return temp1; default: PERROR("EXPRESSION MUST BEGIN WITH FUNCTION OR METHOD CALL");} } Value* parse_frest(){ Value *temp1; Val_List *temp2; switch(inc) {case MTHD: GET_TOKEN; temp2 = parse_symlist(); if (parse_fail_msg.length()) {delete (temp2); return NULL;} temp1 = parse_val_expr(); VERIFY2(temp1, temp2); if (inc==R_PARENS) {GET_TOKEN; return new Value (new Method (temp2, temp1));} else {delete temp1; delete temp2; PERROR ("ONLY ONE EXPRESSION ALLOWED IN METHOD DECLARATION.");} case OBJ_COLON: case SYM_COLON: temp1 = parse_fexpr(); VERIFY1 (temp1); temp2 = parse_exprlist(); if (parse_fail_msg.length()) {delete temp1; return NULL;} temp1->concat (temp2); return temp1; case L_PARENS: case SYM: case RESERVED: temp1 = parse_fexpr(); VERIFY1 (temp1); temp2 = parse_exprlist(); if (!temp2 && parse_fail_msg.length()) {delete temp1; return NULL;} temp1->toexpr(temp2); return temp1; default: PERROR("INVALID EXPRESSION");} } Value* parse_listexpr(Value_Type l_or_ex){ Val_List* temp; Value* temp2; switch(inc) {case L_PARENS: GET_TOKEN; if (inc==MTHD) {temp2 = parse_frest(); return temp2;} temp = parse_listrest(); if (!temp && parse_fail_msg.length()) return NULL; return new Value (temp, l_or_ex); case APOSTROPHE: case OBJ: case NUM: case REAL: case STR: case ERR: case SYM: case RESERVED: case L_BRACKET: return parse_const(); case MTHD: PERROR("EXPECTING A LIST OR A LITERAL AFTER APOSTROPHE (')"); case 0: PERROR("UNEXPECTED END OF EXPRESSION"); case R_BRACKET: PERROR ("CLOSING BRACKET } FOUND WITH NO CORRESPONDING OPEN"); default: PERROR("UNABLE TO PARSE LIST");} } Val_List* parse_listrest(){ Value *temp1; Val_List* temp2; switch (inc) {case R_PARENS: GET_TOKEN; return (Val_List*)NULL; case L_PARENS: temp1 = parse_listexpr(EXPR); break; case APOSTROPHE: case OBJ: case NUM: case REAL: case STR: case RESERVED: case SYM: case L_BRACKET: case ERR: temp1 = parse_const(); break; case MTHD: GET_TOKEN; temp2 = parse_symlist(); if (parse_fail_msg.length()) {delete (temp2); return NULL;} temp1 = parse_val_expr(); VERIFY2(temp1, temp2); if (inc==R_PARENS) temp1 = new Value (new Method (temp2, temp1)); else {delete temp1; delete temp2; PERROR ("ONLY ONE EXPRESSION ALLOWED IN METHOD DECLARATION.");} break; case R_BRACKET: PERROR ("CLOSING BRACKET } FOUND WITH NO CORRESPONDING OPEN"); case 0: PERROR("UNEXPECTED END OF EXPRESSION"); default: PERROR("UNABLE TO PARSE LIST");} VERIFY1 (temp1); temp2 = parse_listrest(); if (!temp2 && parse_fail_msg.length()) {delete temp1; return temp2;} else return new Val_List (temp1, temp2); } Value* parse_const(){ Value* temp; switch(inc) {case APOSTROPHE: GET_TOKEN; temp = parse_listexpr(LIST); if (temp) {if (temp->type == LIST) return temp; else return new Value (new Val_List (new Value (QUOTE , RESERVED), new Val_List (temp)), EXPR);} else return temp; case OBJ: case NUM: case REAL: case STR: case RESERVED: case SYM: case ERR: temp = yylval->grab(); GET_TOKEN; return temp; case R_PARENS: PERROR("EXPECTED A CONSTANT, GOT A )"); case OBJ_COLON: case SYM_COLON: PERROR("INVALID METHOD CALL"); case R_BRACKET: PERROR ("CLOSING BRACKET } FOUND WITH NO CORRESPONDING OPEN"); case L_BRACKET: return parse_user_def(); default: PERROR("INVALID TOKEN -- EXPECTING 'CONST'");} } Val_List* parse_exprlist(){ Value *temp1; Val_List *temp2; switch(inc) {case R_PARENS: GET_TOKEN; return (Val_List*)NULL; case L_PARENS: case APOSTROPHE: case OBJ: case NUM: case REAL: case STR: case RESERVED: case SYM: case L_BRACKET: case ERR: temp1 = parse_val_expr(); VERIFY1 (temp1); temp2 = parse_exprlist(); if (!temp2 && parse_fail_msg.length()) {delete temp1; return temp2;} else return new Val_List (temp1, temp2); case R_BRACKET: PERROR ("CLOSING BRACKET } FOUND WITH NO CORRESPONDING OPEN"); default: PERROR("INVALID METHOD CALLS IN VALUE EXPRESSION");} } Val_List* parse_symlist(){ switch (inc) {case L_PARENS: GET_TOKEN; return parse_symrest(); default: PERROR("METHOD DECLARATIONS REQUIRE A LIST OF VARIABLE NAMES");} } Val_List* parse_symrest(){ Value* temp; switch (inc) {case R_PARENS: GET_TOKEN; return NULL; case SYM: temp = yylval->grab(); GET_TOKEN; return new Val_List (temp, parse_symrest()); default: PERROR("NON-SYMBOL FOUND IN PARAMETER LIST");} } Value* parse_coloned(){ Value* temp1, *temp2, *temp3; switch (inc) {case OBJ_COLON: case SYM_COLON: temp1 = yylval->grab(); GET_TOKEN; if (inc != SYM) {delete temp1; PERROR("OBJECT CALL REQUIRES VALID METHOD NAME");} temp2 = yylval->grab(); GET_TOKEN; temp3 = (new Value (CALL, RESERVED)); temp3->toexpr (new Val_List (temp1, new Val_List (temp2))); return temp3; default: PERROR ("PARSE ERROR IN parse_coloned()");} } Value* parse_user_def(){ Value* ob_type; Value* val; Value* retval; GET_TOKEN; ob_type = parse_val_expr(); if (parse_fail_msg.length()) {delete ob_type; return NULL;} if (ob_type -> get_type() != OBJ) {delete ob_type; PERROR ("USER DEFINED DATA TYPE MUST BE AN OBJECT");} val = parse_val_expr(); if (parse_fail_msg.length()) {delete ob_type; delete val; return NULL;} if (val->get_type() == EXPR) {delete ob_type; delete val; PERROR ("USER-DEFINED DATA VALUE MUST BE A CONSTANT, NOT EXPRESSION");} if (inc != R_BRACKET) {delete ob_type; delete val; PERROR ("EXPECTING '}' AFTER USER-DEFINED DATA");} GET_TOKEN; retval = new Value (ob_type, val); val->release(); ob_type->release(); return retval; }