/* Yacc grammar for Shrdlu blocks world. */ %{ #include #include #include #define YYSTYPE tree #define YYERROR_VERBOSE 1 #define w(X) ((void*)(X)) /* Since these may #include "shrdparse.tab.h", they must come after #define YYSTYPE tree */ #include "assert.h" #include "tree.h" #include "universe.h" #include "why.h" extern int suppress_yyerror; void print_vocabulary(void); void not_a_question(void); void not_a_statement(void); adjective_list build_number(int i); %} %token PUT DESCRIBE QUIT %token A THE ANOTHER %token ON %token BLOCK TABLE RED GREEN BLUE %token YOU YOURSELF %token IT ITSELF %token WHY DID EVERYTHING %token EOL_ Q_ C_ UNKNOWN %token NUMBER /* 0, 1, 2, etc. */ %% input: input something | /* empty */ ; something: | QUIT period EOL_ { YYACCEPT; }; | cmd period EOL_ { verb v = $1; v->u.v.actor = build_noun(w(YOU)); perform(v); }; | WHY DID noun_phrase cmd question EOL_ { verb v = $4; v->u.v.actor = $3; answer(build_question(w(WHY), v)); }; | WHY question EOL_ { why_did_you(NULL, NULL, NULL); }; | DID noun_phrase cmd question EOL_ { verb v = $3; v->u.v.actor = $2; answer(build_question(w(DID), v)); }; | EOL_ { print_vocabulary(); }; | error EOL_ { yyerrok; }; cmd: DESCRIBE noun_phrase { $$ = build_verb(w(DESCRIBE), NULL, $2, NULL, NULL); }; | PUT noun_phrase ON noun_phrase { $$ = build_verb(w(PUT), NULL, $2, w(ON), $4); }; period: C_ ; | Q_ { not_a_question(); YYERROR; }; | /* empty */ ; question: Q_ ; | C_ { not_a_statement(); YYERROR; }; | /* empty */ ; article: A { $$ = w(A); }; | THE { $$ = w(THE); }; | ANOTHER { $$ = w(ANOTHER); }; adjective: RED { $$ = build_adjective(w(RED)); }; | GREEN { $$ = build_adjective(w(GREEN)); }; | BLUE { $$ = build_adjective(w(BLUE)); }; noun: BLOCK { $$ = build_noun(w(BLOCK)); }; | TABLE { $$ = build_noun(w(TABLE)); }; | adjective BLOCK { $$ = append_noun(build_noun(w(BLOCK)), $1); }; noun_phrase: article noun { $$ = append_noun($2, $1); }; | BLOCK number_adj { assert(($2)->word == NULL); $$ = append_noun(build_noun(w(BLOCK)), $2); }; | number_adj { assert(($1)->word == NULL); $$ = append_noun(build_noun(w(BLOCK)), $1); }; | YOU { $$ = build_noun(w(YOU)); }; | YOURSELF { $$ = build_noun(w(YOURSELF)); }; | IT { $$ = build_noun(w(IT)); }; | ITSELF { $$ = build_noun(w(ITSELF)); }; | EVERYTHING { $$ = build_noun(w(EVERYTHING)); }; | EVERYTHING adjective { $$ = append_noun(build_noun(w(EVERYTHING)), $2); }; number_adj: NUMBER { $$ = $1; }; %% #include #include #include "why.h" int suppress_yyerror = 0; int main(void) { init_universe(); yyparse(); return 0; } int yyerror(char *error) { if (suppress_yyerror) { suppress_yyerror = 0; return 0; } /* The lexer takes care of UNKNOWN errors for us! */ if (strstr(error, "UNKNOWN") != NULL) return 0; puts("I DIDN'T UNDERSTAND THAT COMBINATION OF WORDS."); set_why_context(why_dummy, NULL, NULL); new_reason(why_dummy, NULL, NULL, WHY_GRAMMAR, NULL, NULL); return 0; } void print_vocabulary(void) { static int msg = 2; if (!msg) return; msg--; if (msg == 1) { puts("(Blank line was ignored.)"); } else { puts("(Shrdlu recognizes English commands such as:"); puts("PUT BLOCK 2 ON ANOTHER BLOCK"); puts("DESCRIBE IT"); puts("DESCRIBE EVERYTHING"); puts("WHY DID YOU PUT BLOCK 7 ON THE TABLE?"); puts("QUIT"); puts("This is all the help you're getting from me."); puts("I'm going back to ignoring blank lines.)"); } } void not_a_question(void) { puts("THAT DIDN'T LOOK LIKE A QUESTION."); set_why_context(why_dummy, NULL, NULL); new_reason(why_dummy, NULL, NULL, WHY_GRAMMAR, NULL, NULL); } void not_a_statement(void) { puts("THAT DIDN'T LOOK LIKE A STATEMENT."); new_reason(why_dummy, NULL, NULL, WHY_GRAMMAR, NULL, NULL); } /* used in the lexer */ adjective_list build_number(int i) { adjective_list a = malloc(sizeof *a); assert(a != NULL); a->pos = ADJECTIVE_LIST; a->word = NULL; a->u.al.number = i; a->u.al.adjlist = NULL; return a; }