/*
 * Simple PASCAL compiler
 * File name: compiler.c
 * ----------------------
 * This controls the main flow of the compiler. 
 *    Chakma Junan
 *    e993178@edu.tut.ac.jp
 *    Information and Computer Science
 *    Toyohashi University of Technology
 *
 * It was originally implemented by 
 *    ohno@edu.tut.ac.jp
 */
#include <stdio.h>
#include <stdarg.h>
#include "getsym.h"

extern	TOKEN	tok;	
extern	FILE	*infile;
extern	FILE	*outfile;
extern	struct	list	*Table;
extern	int	procedure_flag;

extern	void	statement();
extern	struct	list	*init_table();
extern	int	table(char *, struct list *);
extern	void	procedure();

void compiler();
void outblock();
void error(char *msg, ...);

void compiler()
{
    init_getsym();
    getsym();
    if(tok.attr == RWORD && tok.value == PROGRAM) {
       getsym();
       if(tok.attr == IDENTIFIER) {
	  getsym();
	  if(tok.attr == SYMBOL && tok.value == SEMICOLON) {
	     getsym();
	     outblock();
	     if(tok.attr == SYMBOL && tok.value == PERIOD) {
		fprintf(stderr, "Parsing Completed. No errors found. \n");
	     } else error("At the end, a period is required."); 
	  } else error("line: %d: After Program name, a semicolon is needed.",
			tok.sline);
       } else error("line: %d: Program identifier is needed. ", tok.sline);
    } else error("line: %d: At first, program declaration in required.",
		  tok.sline);
}

/*
 * Function: outblock
 * Usage: outblock();
 * ------------------
 * This function initializes the variable table and allocates
 * necessary places for the variables. Please note that a
 * program without any variables will fail miserably!(You 
 * should make it OK)
 */
void outblock()
{
   Table = init_table();
   /* At the beginning! */
   fprintf(outfile, "      jmp      main \n");
   if(tok.attr == RWORD && tok.value == VAR) {
      do 
      {
         getsym();
	 if(tok.attr == IDENTIFIER) 
	 {
           table(tok.charvalue, Table);
	 } 
      } while(tok.value != SEMICOLON);
   } else error("A var declaration is required. \n"); 
   getsym();
   while(tok.value == PROCEDURE)
   {
      procedure();
      getsym();
   }
   procedure_flag = 0;
   fprintf(outfile, "main: \n");
   statement();
}

/*
 * Function: error
 * Usage: (void) error(char *msg, ...);
 * ------------------------------------
 * This is a typical error function. It prints a message on stderr
 * according to the format passed to it through 'msg'.
 */
void error(char *msg, ...)
{
    va_list args;

    va_start(args, msg);
    fprintf(stderr, "Error: ");
    vfprintf(stderr, msg, args);
    fprintf(stderr, "\n");
    va_end(args);
    exit(1);
}
