/* Yacc grammar for Shrdlu blocks world. */
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 <stdio.h>
#include <stdlib.h>
#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;
}