#include <stdio.h>
#include <stdlib.h>
#include <string.h>

extern int Start_col, Curr_col, Curr_line_num;
extern char Inp_line[512];

static char* Source_name;
char *Ignorables();
char *Ignorable_toks;
char **Token_sets();
char **Tok_set;
char Ignored_tokens[1024], *Ignored_toks;
int Tok;

void import_parser(){}

int clib_Parse(long *fn, long *mode){
  Source_name = object_as_string(fn);
  Tok_set = Token_sets();
  Ignorable_toks = Ignorables();
  Ignored_toks = Ignored_tokens; *Ignored_toks = 0;
  Init_scanner(fn, mode);
  Init_cbuilder();
  Tok = Next_token();
  Parse_goal();
  Skip(1);
};

int Match(char *Toks){
  do{
    if (Tok == 0) Note_error();
    if (strchr(Toks,Tok)) return 1;
    if (strpbrk(Toks,Ignored_tokens)) return 1;
    if (!strchr(Ignorable_toks,Tok)) return 0;
    *Ignored_toks = Tok; Ignored_toks += 1; *Ignored_toks = 0;
    Tok = Next_token();
  }while (1);
};

int Match1(int Tk){
  do{
    if (Tok == 0) Note_error();
    if (Tk == Tok || strchr(Ignored_tokens, Tk)) return 1;
    if (!strchr(Ignorable_toks,Tok)) return 0;
    *Ignored_toks = Tok; Ignored_toks += 1; *Ignored_toks = 0;
    Tok = Next_token();
  }while (1);
};

int Note_error(){
  int i;
  if (Tok == 1)
    fprintf(stderr, "%s(%i) ERROR: Source file ended too soon\n", Source_name, Curr_line_num);
  else{
    fprintf(stderr, "%s(%i, %i) ERROR: Did not expect ", Source_name, Curr_line_num, Start_col+1);
    for (i = Start_col; i < Curr_col; i++) fputc(Inp_line[i], stderr);
    fprintf(stderr, "\n");
  };
  exit(1);
};

int Skip(int Tk){
  char *p = strchr(Ignored_tokens,Tk);
  if (p != NULL){
    do {*p = 127; p = strchr(Ignored_tokens,Tk);} while (p != NULL);
    return;
  };
  while (Tk != Tok){
    if (!strchr(Ignorable_toks,Tok)) Note_error();
    Tok = Next_token();
  };
  Tok = Next_token();
  Ignored_toks = Ignored_tokens;  *Ignored_toks = 0; 
};

int Parse_identifier(){
  if (!Match1(3)) Note_error();
  Build_token("identifier", Inp_line, Start_col, Curr_col);
  Tok = Next_token();
  Ignored_toks = &Ignored_tokens[0]; *Ignored_toks = 0;
};

int Parse_number(){
  if (!Match1(4)) Note_error();
  Build_token("number", Inp_line, Start_col, Curr_col);
  Tok = Next_token();
  Ignored_toks = &Ignored_tokens[0]; *Ignored_toks = 0;
};

int Parse_string(){
  if (!Match1(5)) Note_error();
  Build_token("string", Inp_line, Start_col, Curr_col);
  Tok = Next_token();
  Ignored_toks = &Ignored_tokens[0]; *Ignored_toks = 0;
};

char *Ignorables(){
  char *igs = malloc(3);
  igs[0] = 2;
  igs[1] = 10;
  igs[2] = 0;
  return igs;
};

int Parse_list_of_alternatives(){
  Build_start_list();
  Parse_clause_list();
  Build_add_to_list();
  while (Match1(8)){
    Skip(8);
    Parse_clause_list();
    Build_add_to_list();
  };
};

int Parse_rule(){
  Parse_identifier();
  Skip(9);
  Parse_list_of_alternatives();
  Build_rulee();
};

int Parse_goal(){
  while (Match1(3)){
    Parse_rule();
  };
  Build_goal();
};

int Parse_clause(){
  if (Match1(3)){
    Parse_identifier();
    Build_idclause();
  }else if (Match1(5)){
    Parse_string();
    Build_strclause();
  }else if (Match1(14)){
    Skip(14);
    Parse_list_of_alternatives();
    Skip(16);
    Build_sqclause();
  }else if (Match1(15)){
    Skip(15);
    Parse_list_of_alternatives();
    Skip(17);
    Build_curclause();
  }else if (Match1(12)){
    Skip(12);
    Parse_list_of_alternatives();
    Skip(13);
    Build_rouclause();
  }else if (Match1(6)){
    Skip(6);
    Parse_identifier();
    if (Match1(4)){
      Parse_number();
    }else{
      Build_nopars();
    };
    Skip(7);
    Build_angclause();
  }else{
    Note_error();
  };
};

int Parse_clause_list(){
  Build_start_list();
  Parse_clause();
  Build_add_to_list();
  while (Match(Tok_set[0])){
    if (Match1(2)){
      /*Eol already skipped*/ break;
    }else{
      if (Match1(11)){
        Skip(11);
      };
      Parse_clause();
      Build_add_to_list();
    };
  };
};

char **Token_sets(){
  char** ts = malloc(4);
  ts[0] = malloc(9);
  ts[0][0] = 2;
  ts[0][1] = 3;
  ts[0][2] = 5;
  ts[0][3] = 6;
  ts[0][4] = 11;
  ts[0][5] = 12;
  ts[0][6] = 14;
  ts[0][7] = 15;
  ts[0][8] = 0;
  return ts;
};
