1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/* SI 413 Fall 2012
 * Lab 7
 * Parser for SPL that just shows the parse tree
 * This parser uses a simpler grammar with assoc/prec specifications.
 */
 
// This code is included in the spl.tab.hpp header file
%code requires {
 
#include <cstdlib>
#include <iostream>
using namespace std;
 
#include "ast.hpp"
 
int yylex(); 
 
} // end header file part
 
// This code is only included in the parser file spl.tab.cpp
%code {
 
// These are the colored output streams to make things all pretty.
colorout resout(1, 'u');
colorout errout(2, 'r');
 
// Global variable will be set to the entire AST.
Stmt* tree;
 
// Global variable to indicate if an error has occurred.
bool error;
 
// Global variable to indicate that terminal input is "live" and
// so prompts should be displayed.
bool showPrompt;
 
// This is the C file that flex reads from for scanning.
extern FILE* yyin;
 
void yyerror(const char *p) { 
  if (! error) {
    errout << "Parser error: " << p << endl; 
    error = true;
  }
}
 
} // end top of parser part
 
  /* Tell bison to give descriptive error mesages. */
%error-verbose
 
%union {
  Block* block;
  Stmt* stmt;
  Exp* exp;
  Id* id;
  Oper op;
};
 
%left<op> BOP
%right<op> NOTTOK
%left<op> COMP
%left<op> OPA
%left<op> OPM
%right POSNEG
%left FUNARG
 
%token LC RC LP RP LAMBDA IF IFELSE WHILE READ WRITE NEW ASN STOP
%token<id> ID
%token<exp> NUM BOOL
%type<stmt> stmt stmtlist
%type<block> block
%type<exp> exp
 
%%
  /*Note: YYACCEPT is a bison macro that just tells it to quit parsing.*/
res: stmt { tree = $1; YYACCEPT; }
|         { tree = NULL; }
 
block: LC stmtlist RC { $$ = new Block($2); }
 
stmtlist: stmtlist stmt { $$ = Stmt::append($1,$2); }
|                       { $$ = new NullStmt; }
 
stmt: NEW ID ASN exp STOP    {$$ = new NewStmt($2,$4);}
|     ID ASN exp STOP        {$$ = new Asn($1,$3);}
|     WRITE exp STOP         {$$ = new Write($2);}
|     IF exp block           {$$ = new IfStmt($2,$3,new NullStmt());}
|     IFELSE exp block block {$$ = new IfStmt($2,$3,$4);}
|     WHILE exp block        {$$ = new WhileStmt($2,$3);}
|     block                  {$$ = $1;}
 
exp: exp BOP exp          {$$ = new BoolOp($1,$2,$3);}
|    NOTTOK exp           {$$ = new NotOp($2);}
|    exp COMP exp         {$$ = new CompOp($1,$2,$3);}
|    exp OPA exp          {$$ = new ArithOp($1,$2,$3);}
|    exp OPM exp          {$$ = new ArithOp($1,$2,$3);}
|    OPA exp %prec POSNEG {$$ = ($1 == ADD ? $2 : new NegOp($2));}
|    READ                 {$$ = new Read();}
|    LAMBDA ID block      {$$ = new Lambda($2,$3);}
|    exp FUNARG exp       {$$ = new Funcall($1,$3);}
|    LP exp RP            {$$ = $2;}
|    ID                   {$$ = $1;}
|    NUM                  {$$ = $1;}
|    BOOL                 {$$ = $1;}
 
%%
int main(int argc, char** argv) {
  showPrompt = isatty(0) && isatty(2);
  bool interactive = showPrompt;
 
  if (argc >= 2) {
    if (!(yyin = fopen(argv[1],"r"))) {
      cerr << "Could not open input file \"" << argv[1] << "\"!" << endl;
      exit(2);
    }
    interactive = false;
  }
 
  if (interactive) {
    bool showAST = true; // set to false to stop the AST from popping up.
    // This is the "interactive" version of the interpreter.
    // It keeps going, even if there are errors, and prints out
    // prompts and such.
    while(true) {
      tree = NULL;
      error = false;
      cerr << "spl> ";
      yyparse();
      if (tree == NULL && ! error) break;
      else if (tree != NULL) {
        tree->writeDot("spl.dot");
        system("dot -Tpdf spl.dot > spl.pdf");
        if (showAST) system("evince spl.pdf > /dev/null 2>&1 &");
        tree->exec();
      }
    }
    cerr << "Goodbye" << endl;
  }
  else {
    // This is the non-interactive version of the interpreter.
    // It exits with return code 5 if there is any kind of error,
    // and doesn't display prompts or other niceties.
    error = false;
    while(! error) {
      tree = NULL;
      if (yyparse() != 0 || error || tree == NULL) break;
      tree->writeDot("spl.dot");
      system("dot -Tpdf spl.dot > spl.pdf");
      tree->exec();
    }
    if (error) return 5;
  }
 
  return 0;
}