/*******************************************************************************
*
* GTB release 2.0 by Adrian Johnstone (A.Johnstone@rhul.ac.uk) 21 March 2003
*
* gtb_rd.c - recursive secent parser functions
*
* This file may be freely distributed. Please mail improvements to the author.
*
*******************************************************************************/
#include <string.h>
#include <ctype.h>
#include "graph.h"
#include "memalloc.h"
#include "textio.h"
#include "gtb.h"
#include "gtb_gram.h"
#include "gtb_scr.h"
#include <stdio.h>

void rd_print_header(void)
{
  text_printf("/******************************************************************************\n");
  text_printf("*\n");
  text_printf("* GRD parser generated by " GTB_VERSION " on ");
  text_print_time();
  text_printf("\n*\n");
  text_printf("******************************************************************************/\n\n");
}

void rd_print_prototypes(grammar *this_gram)
{
  text_printf("// Parser function prototypes\n");
  for (gram_symbols_data *this_symbol = (gram_symbols_data*) symbol_next_symbol_in_scope(symbol_get_scope(this_gram->symbol_table));
       this_symbol != NULL;
       this_symbol = (gram_symbols_data*) symbol_next_symbol_in_scope(this_symbol)
       )
    if (this_symbol->name_space == SCRIPT_NS_TERMINAL || this_symbol->name_space == SCRIPT_NS_NONTERMINAL)
    {
      text_printf("int gtb_match_");
      text_print_as_C_identifier(this_symbol->id);
      text_printf("(void);\n");
    }
}

void rd_print_bodies(grammar *this_gram)
{
  text_printf("\n// Parser function bodies\n");

  for (gram_symbols_data *this_symbol = (gram_symbols_data*) symbol_next_symbol_in_scope(symbol_get_scope(this_gram->symbol_table));
       this_symbol != NULL;
       this_symbol = (gram_symbols_data*) symbol_next_symbol_in_scope(this_symbol)
       )
    if (this_symbol->name_space == SCRIPT_NS_TERMINAL || this_symbol->name_space == SCRIPT_NS_NONTERMINAL)
    {
      text_printf("int gtb_match_");
      text_print_as_C_identifier(this_symbol->id);
      text_printf("(void)\n{\n");

      if (this_symbol->rule_tree == NULL)
        text_printf("  return strncmp(cc, \"%s\", %i) == 0;\n", this_symbol->id, strlen(this_symbol->id));
      else
      {
        for (gram_edge *this_production_edge = (gram_edge*) graph_next_out_edge(this_symbol->rule_tree);
             this_production_edge != NULL;
             this_production_edge = (gram_edge*) graph_next_out_edge(this_production_edge))
        {
          text_printf("  ");
          for (gram_edge *this_element_edge = ((gram_edge*) graph_next_out_edge(graph_destination(this_production_edge)));
               this_element_edge != NULL;
               this_element_edge = (gram_edge*) graph_next_out_edge(graph_destination(this_element_edge)))
          {
            gram_symbols_data *this_element = this_element_edge->symbol_table_entry;

            text_printf("gtb_match_");
            text_print_as_C_identifier(this_element->id);
            text_printf("(); ");
          }
          text_printf("\n");
        }
      }
      text_printf("}\n\n");
    }
}

void rd_print_main(grammar *this_gram)
{
  text_printf("int main(void)\n{\n  gtb_match_");
  text_print_as_C_identifier(this_gram->start_rule->id);
  text_printf("();\n}\n");
}

void rd_grd_parse(grammar *this_gram, char *filename)
{
  char *parser_filename = text_force_filetype(filename, "cpp");
  FILE *parser_file = fopen((parser_filename), "w");

  if (parser_file == NULL)
    text_message(TEXT_FATAL, "unable to open GRD parser file '%s' for write\n", parser_filename);

  text_redirect(parser_file);

  rd_print_header();
  rd_print_prototypes(this_gram);
  rd_print_bodies(this_gram);
  rd_print_main(this_gram);

  text_redirect(stdout);
  fclose(parser_file);
}

