/* SI 413 Fall 2021
 * Lab 6
 * Parser for pat that just shows the parse tree
 * YOUR NAME HERE
 */

%code requires {

#include <cstdlib>
#include <iostream>
#include "colorout.hpp"
#include "parsetree.hpp"
using namespace std;

// This says that semantic values of tokens should be ParseTree pointers.
#define YYSTYPE ParseTree*

int yylex();
extern colorout resout;
extern colorout errout;

}

%code {

int yyerror(const char *p) {
  errout << "Parser error: " << p << endl;
  exit(1);
}

ParseTree* tree = NULL; // This global will be set to the whole parse tree.

// Global variable to indicate to stop parsing.
bool done = false;

// These are the colored output streams to make things all pretty.
colorout resout(1, 'u');
colorout errout(2, 'r');

}

  /* Tell bison to give descriptive error mesages. */
%define parse.error verbose

  /* This defines the tokens. You will have to change this to
     set their precedence and associativity!
   */
%token STOP FOLD COLON REV SYM NAME LB RB

%%

  /*Note: YYACCEPT is a bison macro that just tells it to quit parsing.*/
S: seq STOP              { tree = $1; YYACCEPT; }
|                        { done = true; }

seq: seq FOLD catseq     {$$ = new ParseTree("seq",$1,$2,$3);}
|    catseq              {$$ = new ParseTree("seq",$1);}

catseq: catseq opseq     {$$ = new ParseTree("catseq",$1,$2);}
|       opseq            {$$ = new ParseTree("catseq",$1);}

opseq: opseq COLON NAME  {$$ = new ParseTree("opseq",$1,$2,$3);}
|      opseq REV         {$$ = new ParseTree("opseq",$1,$2);}
|      atom              {$$ = new ParseTree("opseq",$1);}

atom: SYM                {$$ = new ParseTree("atom",$1);}
|     NAME               {$$ = new ParseTree("atom",$1);}
|     LB seq RB          {$$ = new ParseTree("atom",$1,$2,$3);}

%%
int main()
{
  // This checks whether the output is a terminal.
  bool tty = isatty(0) && isatty(2);

  while(true) {
    if (tty) cerr << "> ";
    yyparse();
    if (done) break;
    if (isatty(1)) {
      // try to create parse tree pdf and display it
      tree->writeDot("pat.dot");
      if(system("dot -Tpdf pat.dot >pat.pdf") == 0) {
        if (system("evince pat.pdf >/dev/null 2>&1 &") != 0) {
          resout << "tree created in pat.pdf" << endl;
        }
      }
      else {
        errout << "error creating pat.pdf. Try 'sudo apt install graphviz'" << endl;
      }
    }
    else {
      // not running on a terminal, so do a textual representation of the tree.
      tree->writeTo(resout);
    }
    delete tree;
  }

  if (tty) cerr << "Goodbye!" << endl;

  // Try to kill off any parse tree windows that are hanging around
  (void)!system("kill `pgrep -f \"evince pat.pdf\"`");

  return 0;
}