#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_float(){
  if (!Match1(4)) Note_error();
  Build_token("float", Inp_line, Start_col, Curr_col);
  Tok = Next_token();
  Ignored_toks = &Ignored_tokens[0]; *Ignored_toks = 0;
};

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

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

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

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

char *Ignorables(){
  char *igs = malloc(5);
  igs[0] = 2;
  igs[1] = 7;
  igs[2] = 8;
  igs[3] = 26;
  igs[4] = 0;
  return igs;
};

int Parse_get(){
  Skip(48);
  Parse_identifier();
  Build_get_input();
};

int Parse_expr(){
  if (Match(Tok_set[0])){
    if (Match1(35)){
      Skip(35);
    }else if (Match1(60)){
      Skip(60);
    }else{
      Note_error();
    };
    Parse_sexpr();
    Build_unary_minus_op();
  }else if (Match1(22)){
    Skip(22);
    Parse_sexpr();
    Build_count_op();
  }else if (Match(Tok_set[1])){
    Parse_sexpr();
  }else{
    Note_error();
  };
};

int Parse_iterator(){
  Parse_identifiers();
  Skip(68);
  Parse_expression();
  Build_new_iterator();
  while (Match1(31)){
    Skip(31);
    Parse_identifiers();
    Skip(68);
    Parse_expression();
    Build_lazy();
    Build_new_nested_iterator();
  };
  if (Match(Tok_set[2])){
    if (Match1(12)){
      Skip(12);
    }else if (Match1(18)){
      Skip(18);
    }else{
      Note_error();
    };
    Parse_expression();
    Build_lazy();
    Build_new_filter();
  };
};

int Parse_put(){
  Skip(69);
  Parse_expression();
  Build_put_value_op();
};

int Parse_while_loop(){
  Skip(17);
  Parse_expression();
  Build_lazy();
  if (Match1(65)){
    Skip(65);
  };
  Parse_instructions();
  Skip(44);
  Build_while_loop();
};

int Parse_slot(){
  Parse_identifier();
  Build_new_slot_type();
  if (Match1(27)){
    Parse_parameter_declarations();
    Build_parameters();
  };
  Skip(46);
  Parse_type();
  Build_type();
  if (Match1(81)){
    Skip(81);
    Build_save_pos();
    Parse_expression();
    Build_lazy_with_pos();
    Build_initial_expression();
  };
  if (Match1(48)){
    Skip(48);
    Parse_instructions();
    Build_continuations();
    Build_get_method();
  };
  if (Match1(59)){
    Skip(59);
    Parse_instructions();
    Build_continuations();
    Build_set_method();
  };
  if (Match1(41)){
    Skip(41);
  };
};

int Parse_identifiers(){
  Build_start_list();
  Parse_identifier();
  Build_add_to_list();
  while (Match1(31)){
    Skip(31);
    Parse_identifier();
    Build_add_to_list();
  };
};

int Parse_insert(){
  Skip(15);
  Parse_expression();
  Skip(42);
  Parse_component_identifier();
  Build_add_prototype();
};

int Parse_expressions(){
  Build_start_list();
  Parse_expression();
  Build_add_to_list();
  while (Match(Tok_set[3])){
    if (Match1(31)){
      Skip(31);
    };
    Parse_expression();
    Build_add_to_list();
  };
};

int Parse_conditional_instruction(){
  if (Match1(19)){
    Skip(19);
    if (Match1(2)){
      /*Eol already skipped*/
      Build_return();
    }else if (Match(Tok_set[4])){
      Parse_expression();
      Build_return_with_result();
    }else{
      Build_return();
    };
  }else if (Match1(45)){
    Skip(45);
    if (Match1(2)){
      /*Eol already skipped*/
      Build_exit();
    }else if (Match1(5)){
      Parse_integer();
      Build_multi_exit();
    }else{
      Build_exit();
    };
  }else if (Match1(3)){
    Parse_assignment_or_procedure_call();
  }else{
    Note_error();
  };
  if (Match1(37)){
    Skip(37);
    Parse_expression();
    Build_when();
  };
};

int Parse_delete(){
  Skip(80);
  Parse_expression();
  Skip(39);
  Parse_component_identifier();
  Build_remove_prototype();
};

int Parse_parameter_declarations(){
  Build_start_list();
  if (Match1(27)){
    Skip(27);
    Parse_parameter_declaration();
    while (Match(Tok_set[5])){
      if (Match1(31)){
        Skip(31);
      };
      Parse_parameter_declaration();
    };
    Skip(28);
  };
};

int Parse_relation(){
  Parse_arith_expr();
  if (Match1(62)){
    Skip(62);
    if (Match1(68)){
      Skip(68);
      Parse_arith_expr();
      Build_in_op();
      Build_not_op();
    }else if (Match1(16)){
      Skip(16);
      Parse_arith_expr();
      Build_subset_op();
      Build_not_op();
    }else{
      Note_error();
    };
  }else if (Match1(68)){
    Skip(68);
    Parse_arith_expr();
    Build_in_op();
  }else if (Match1(16)){
    Skip(16);
    Parse_arith_expr();
    Build_subset_op();
  }else if (Match1(78)){
    Skip(78);
    Parse_arith_expr();
    Build_not_equal_op();
  }else if (Match1(51)){
    Skip(51);
    Parse_arith_expr();
    Build_equal_op();
  }else if (Match1(53)){
    Skip(53);
    Parse_arith_expr();
    Build_less_than_op();
  }else if (Match1(82)){
    Skip(82);
    Parse_arith_expr();
    Build_less_than_or_equal_op();
  }else if (Match1(54)){
    Skip(54);
    Parse_arith_expr();
    Build_greater_than_op();
  }else if (Match1(86)){
    Skip(86);
    Parse_arith_expr();
    Build_greater_than_or_equal_op();
  };
};

int Parse_list(){
  if (Match1(71)){
    Skip(71);
  }else if (Match1(87)){
    Skip(87);
  }else{
    Note_error();
  };
  if (Match(Tok_set[4])){
    Parse_expression();
    if (Match1(46)){
      Skip(46);
      Build_lazy();
      Parse_iterator();
      Build_new_iterated_list();
    }else if (Match1(31)){
      Skip(31);
      Parse_expression();
      Skip(72);
      Parse_expression();
      Build_new_stepped_range_list();
    }else if (Match1(72)){
      Skip(72);
      Parse_expression();
      Build_new_range_list();
    }else if (Match(Tok_set[4])){
      Parse_expressions();
      Build_add_to_front_of_list();
      Build_new_enumerated_list();
    }else{
      Build_start_list();
      Build_add_to_front_of_list();
      Build_new_enumerated_list();
    };
  }else{
    Build_start_list();
    Build_new_enumerated_list();
  };
  Skip(73);
};

int Parse_sexpr(){
  if (Match1(3)){
    Parse_identifier();
    Build_value();
    if (Match(Tok_set[6])){
      Parse_qualifier();
    };
  }else if (Match1(4)){
    Parse_float();
  }else if (Match1(5)){
    Parse_integer();
  }else if (Match1(6)){
    Parse_string();
  }else if (Match(Tok_set[7])){
    Parse_list();
  }else if (Match1(88)){
    Parse_set();
  }else if (Match1(27)){
    Skip(27);
    Parse_expression();
    Skip(28);
  }else if (Match1(58)){
    Skip(58);
    Parse_component_identifier();
    if (Match1(27)){
      Skip(27);
      Parse_expressions();
      Skip(28);
    }else{
      Build_start_list();
    };
    Build_new_component_instance();
  }else{
    Note_error();
  };
};

int Parse_component(){
  Skip(64);
  Parse_identifier();
  Build_new_component();
  if (Match1(76)){
    Skip(76);
    Parse_identifier();
    Build_mark_as_external();
  };
  if (Match1(85)){
    Skip(85);
    Parse_component_identifiers();
    Build_extend();
  };
  if (Match1(50)){
    Skip(50);
    Parse_component_identifiers();
    Build_implement();
  };
  Skip(47);
  Parse_slots();
  Build_with_slots();
};

int Parse_for_loop(){
  Skip(55);
  Parse_iterator();
  if (Match1(65)){
    Skip(65);
  };
  Parse_instructions();
  Skip(44);
  Build_for_loop();
};

int Parse_parameter_declaration(){
  Parse_identifiers();
  Skip(46);
  Parse_type();
  Build_typed_params();
};

int Parse_goal(){
  Parse_component();
};

int Parse_expression(){
  Parse_express();
  if (Match1(84)){
    Skip(84);
    Build_lazy();
    Parse_iterator();
    Build_swap();
    Build_forsome_op();
  }else if (Match1(9)){
    Skip(9);
    Build_lazy();
    Parse_iterator();
    Build_swap();
    Build_forall_op();
  };
};

int Parse_arith_expr(){
  Parse_term();
  while (Match(Tok_set[8])){
    if (Match1(30)){
      Skip(30);
      Parse_term();
      Build_plus_op();
    }else{
      if (Match1(35)){
        Skip(35);
      }else if (Match1(79)){
        Skip(79);
      }else{
        Note_error();
      };
      Parse_term();
      Build_minus_op();
    };
  };
};

int Parse_component_identifiers(){
  Build_start_list();
  Parse_component_identifier();
  Build_add_to_list();
  while (Match(Tok_set[5])){
    if (Match1(31)){
      Skip(31);
    };
    Parse_component_identifier();
    Build_add_to_list();
  };
};

int Parse_express(){
  Parse_conjunction();
  while (Match1(75)){
    Skip(75);
    Parse_conjunction();
    Build_lazy();
    Build_or_op();
  };
};

int Parse_assignment_or_procedure_call(){
  Parse_targets();
  if (Match1(81)){
    Skip(81);
    Parse_expression();
    Build_assign();
  }else if (Match1(21)){
    Skip(21);
    Parse_expression();
    Build_plus_assign();
  }else if (Match(Tok_set[9])){
    if (Match1(23)){
      Skip(23);
    }else if (Match1(52)){
      Skip(52);
    }else{
      Note_error();
    };
    Parse_expression();
    Build_minus_assign();
  }else if (Match1(25)){
    Skip(25);
    Parse_expression();
    Build_divide_assign();
  }else if (Match1(20)){
    Skip(20);
    Parse_expression();
    Build_multiply_assign();
  }else{
    Build_call_as_procedure();
  };
};

int Parse_type(){
  if (Match1(3)){
    Parse_component_identifier();
  }else if (Match1(49)){
    Skip(49);
    Skip(66);
    Parse_type();
    Build_new_list_of();
  }else if (Match1(59)){
    Skip(59);
    Skip(66);
    Parse_type();
    Build_new_set_of();
  }else{
    Note_error();
  };
};

int Parse_if_then_elsif_else(){
  Skip(61);
  Parse_expression();
  if (Match1(34)){
    Skip(34);
  };
  Parse_instructions();
  if (Match1(14)){
    Parse_elsif();
  }else if (Match1(29)){
    Parse_else();
  }else{
    Build_if_then();
  };
  Skip(41);
};

int Parse_component_identifier(){
  Parse_identifier();
  Build_lookup_component();
  while (Match1(33)){
    Skip(33);
    Parse_identifier();
    Build_lookup_lib_component();
  };
};

int Parse_conjunction(){
  Parse_negation();
  while (Match1(38)){
    Skip(38);
    Parse_negation();
    Build_lazy();
    Build_and_op();
  };
};

int Parse_instructions(){
  Build_start_instructions();
  while (Match(Tok_set[10])){
    Parse_instruction();
    if (Match1(43)){
      Skip(43);
    };
    Build_add_instruction();
  };
  Build_lazy();
};

int Parse_term(){
  Parse_factor();
  while (Match(Tok_set[11])){
    if (Match1(63)){
      Skip(63);
      Parse_factor();
      Build_intersect_op();
    }else if (Match1(36)){
      Skip(36);
      Parse_factor();
      Build_multiply_op();
    }else{
      Skip(40);
      Parse_factor();
      Build_divide_op();
    };
  };
};

int Parse_targets(){
  Build_start_list();
  Parse_target();
  Build_add_to_list();
  while (Match1(31)){
    Skip(31);
    Parse_target();
    Build_add_to_list();
  };
  Build_new_target_list();
};

int Parse_qualifier(){
  if (Match1(33)){
    Skip(33);
    Parse_identifier();
    if (Match1(27)){
      Skip(27);
      Parse_expressions();
      Skip(28);
      Build_call_slot_op();
    }else{
      Build_slot_value_op();
    };
    if (Match(Tok_set[6])){
      Parse_qualifier();
    };
  }else if (Match1(27)){
    Skip(27);
    Parse_expressions();
    Skip(28);
    Build_call_op();
    if (Match(Tok_set[6])){
      Parse_qualifier();
    };
  }else if (Match1(71)){
    Skip(71);
    Parse_range();
    Skip(73);
    Build_index_op();
    if (Match(Tok_set[6])){
      Parse_qualifier();
    };
  }else{
    Note_error();
  };
};

int Parse_slots(){
  Build_start_list();
  Parse_slot();
  Build_add_to_list();
  while (Match1(3)){
    Parse_slot();
    Build_add_to_list();
  };
};

int Parse_negation(){
  if (Match1(62)){
    Skip(62);
    Parse_relation();
    Build_not_op();
  }else if (Match(Tok_set[12])){
    Parse_relation();
  }else{
    Note_error();
  };
};

int Parse_elsif(){
  Skip(14);
  Parse_expression();
  if (Match1(34)){
    Skip(34);
  };
  Parse_instructions();
  if (Match1(14)){
    Parse_elsif();
  }else if (Match1(29)){
    Parse_else();
  }else{
    Build_if_then();
  };
  Build_lazy();
  Build_if_then_else();
};

int Parse_set(){
  Skip(88);
  if (Match(Tok_set[4])){
    Parse_expression();
    if (Match1(46)){
      Skip(46);
      Build_lazy();
      Parse_iterator();
      Build_new_iterated_set();
    }else if (Match1(31)){
      Skip(31);
      Parse_expression();
      Skip(72);
      Parse_expression();
      Build_new_stepped_range_set();
    }else if (Match1(72)){
      Skip(72);
      Parse_expression();
      Build_new_range_set();
    }else if (Match(Tok_set[4])){
      Parse_expressions();
      Build_add_to_front_of_list();
      Build_new_enumerated_set();
    }else{
      Build_start_list();
      Build_add_to_front_of_list();
      Build_new_enumerated_set();
    };
  }else{
    Build_start_list();
    Build_new_enumerated_set();
  };
  Skip(11);
};

int Parse_factor(){
  Parse_def_expr();
  if (Match1(67)){
    Skip(67);
    Parse_factor();
    Build_exponentiate_op();
  };
};

int Parse_else(){
  Skip(29);
  Parse_instructions();
  Build_if_then_else();
};

int Parse_instruction(){
  if (Match1(13)){
    Parse_assert();
  }else if (Match(Tok_set[13])){
    Parse_conditional_instruction();
  }else if (Match1(48)){
    Parse_get();
  }else if (Match1(69)){
    Parse_put();
  }else if (Match1(15)){
    Parse_insert();
  }else if (Match1(80)){
    Parse_delete();
  }else if (Match1(55)){
    Parse_for_loop();
  }else if (Match1(61)){
    Parse_if_then_elsif_else();
  }else if (Match1(10)){
    Parse_repeat_loop();
  }else if (Match1(17)){
    Parse_while_loop();
  }else{
    Note_error();
  };
};

int Parse_def_expr(){
  Parse_expr();
  if (Match1(56)){
    Skip(56);
    Parse_expr();
    Build_lazy();
    Build_if_def_op();
  };
};

int Parse_range(){
  if (Match(Tok_set[4])){
    Parse_expression();
    if (Match1(72)){
      Skip(72);
      if (Match(Tok_set[4])){
        Parse_expression();
      }else{
        Build_maxint();
      };
      Build_new_range();
    };
  }else if (Match1(72)){
    Skip(72);
    Build_one();
    Parse_expression();
    Build_new_range();
  }else{
    Note_error();
  };
};

int Parse_assert(){
  Skip(13);
  Parse_expression();
  Build_assert_op();
};

int Parse_target(){
  Parse_identifier();
  Build_new_target();
  while (Match(Tok_set[6])){
    if (Match1(33)){
      Skip(33);
      Parse_identifier();
      Build_qualify();
    }else if (Match1(27)){
      Skip(27);
      Parse_expressions();
      Skip(28);
      Build_parameterize();
    }else{
      Skip(71);
      Parse_expression();
      Skip(73);
      Build_subscript();
    };
  };
};

int Parse_repeat_loop(){
  Skip(10);
  Parse_instructions();
  if (Match1(44)){
    Skip(44);
    Build_repeat_loop();
  }else if (Match1(32)){
    Skip(32);
    Parse_expression();
    Build_lazy();
    Build_repeat_until();
  }else{
    Note_error();
  };
};

char **Token_sets(){
  char** ts = malloc(56);
  ts[0] = malloc(3);
  ts[0][0] = 35;
  ts[0][1] = 60;
  ts[0][2] = 0;
  ts[5] = malloc(3);
  ts[5][0] = 3;
  ts[5][1] = 31;
  ts[5][2] = 0;
  ts[6] = malloc(4);
  ts[6][0] = 33;
  ts[6][1] = 71;
  ts[6][2] = 27;
  ts[6][3] = 0;
  ts[13] = malloc(4);
  ts[13][0] = 19;
  ts[13][1] = 3;
  ts[13][2] = 45;
  ts[13][3] = 0;
  ts[9] = malloc(3);
  ts[9][0] = 52;
  ts[9][1] = 23;
  ts[9][2] = 0;
  ts[11] = malloc(4);
  ts[11][0] = 36;
  ts[11][1] = 40;
  ts[11][2] = 63;
  ts[11][3] = 0;
  ts[3] = malloc(15);
  ts[3][0] = 35;
  ts[3][1] = 3;
  ts[3][2] = 4;
  ts[3][3] = 5;
  ts[3][4] = 6;
  ts[3][5] = 71;
  ts[3][6] = 22;
  ts[3][7] = 87;
  ts[3][8] = 88;
  ts[3][9] = 58;
  ts[3][10] = 27;
  ts[3][11] = 60;
  ts[3][12] = 62;
  ts[3][13] = 31;
  ts[3][14] = 0;
  ts[4] = malloc(14);
  ts[4][0] = 35;
  ts[4][1] = 3;
  ts[4][2] = 4;
  ts[4][3] = 5;
  ts[4][4] = 6;
  ts[4][5] = 71;
  ts[4][6] = 22;
  ts[4][7] = 87;
  ts[4][8] = 88;
  ts[4][9] = 58;
  ts[4][10] = 27;
  ts[4][11] = 60;
  ts[4][12] = 62;
  ts[4][13] = 0;
  ts[8] = malloc(4);
  ts[8][0] = 35;
  ts[8][1] = 30;
  ts[8][2] = 79;
  ts[8][3] = 0;
  ts[12] = malloc(13);
  ts[12][0] = 35;
  ts[12][1] = 3;
  ts[12][2] = 4;
  ts[12][3] = 22;
  ts[12][4] = 5;
  ts[12][5] = 6;
  ts[12][6] = 71;
  ts[12][7] = 87;
  ts[12][8] = 88;
  ts[12][9] = 60;
  ts[12][10] = 58;
  ts[12][11] = 27;
  ts[12][12] = 0;
  ts[10] = malloc(13);
  ts[10][0] = 48;
  ts[10][1] = 80;
  ts[10][2] = 17;
  ts[10][3] = 19;
  ts[10][4] = 3;
  ts[10][5] = 69;
  ts[10][6] = 15;
  ts[10][7] = 55;
  ts[10][8] = 10;
  ts[10][9] = 61;
  ts[10][10] = 13;
  ts[10][11] = 45;
  ts[10][12] = 0;
  ts[1] = malloc(10);
  ts[1][0] = 3;
  ts[1][1] = 4;
  ts[1][2] = 5;
  ts[1][3] = 6;
  ts[1][4] = 71;
  ts[1][5] = 87;
  ts[1][6] = 88;
  ts[1][7] = 58;
  ts[1][8] = 27;
  ts[1][9] = 0;
  ts[7] = malloc(3);
  ts[7][0] = 71;
  ts[7][1] = 87;
  ts[7][2] = 0;
  ts[2] = malloc(3);
  ts[2][0] = 18;
  ts[2][1] = 12;
  ts[2][2] = 0;
  return ts;
};
