#include <stdio.h>
#include "cdefs.h"

FILE *Source;
cptr Source_name;
char Inp_line[512];
int Start_col;
int Curr_col = 0;
int Curr_line_num = 1;
int Tok;
int Indent = 0;
int Indent_offset = 0;

#define Open_quote(c) (c == '`')
#define Close_quote(c) (c == '\'')
#define Backslash(c) (c == '\\')
#define Quote(c) (c == '\"')
#define Eol(c) (c == 13 || c == 10 || c == 0)
#define Charr(c) (c >= '\001' && c <= '\177')
#define Char(c) (c >= '\001' && c <= '\177')
#define Digit(c) (c >= '0' && c <= '9')
#define Hex_digit(c) ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'))
#define Up_let(c) (c >= 'A' && c <= 'Z')
#define Low_let(c) (c >= 'a' && c <= 'z')

void Build_indent(){
  Indent += 2;
  if (Tok == 2) Indent_offset -= 2; else Indent_offset = 0;
}

void Build_outdent(){
  Indent -= 2;
  if (Tok == 2) Indent_offset += 2; else Indent_offset = 0;
}

void Indent_error(){
  string_put_on(Source_name, stderr, 1, Source_name[3]);
  fprintf(stderr, "(%i) ERROR: Incorrect indentation", Curr_line_num);
  exit(3);
}

void Build_check_indent(){
  if (Indent_offset != 0) Indent_error();
}

void Check_indent(){
  while (Inp_line[Curr_col] == ' ') Curr_col += 1;
  if (Inp_line[Curr_col] == 10){
    if (fgets(Inp_line,512,Source) == NULL) Inp_line[0] = 127;
    Curr_line_num += 1; Curr_col = 0; Start_col = 0;
    Check_indent();
  }else{
    if (Inp_line[Curr_col] == 127) return;
    Indent_offset = Curr_col - Indent;
  };
}

void import_scanner(){}

void Init_scanner(cptr fn, cptr mode){
  cptr f;
  fn[1] += 2; mode[1] += 1;
  f = clib_Open(fn, mode);
  Source = (FILE*)(f[2]); Source_name = fn;
  if (Source==NULL){
    fprintf(stderr, "ERROR: can't open ");
    string_put_on(fn, stderr, 1, fn[3]);
    fprintf(stderr, "\n");
    exit(2);
  };
  if (fgets(Inp_line,512,Source) == NULL) Inp_line[0] = 127;
  Curr_col = 0;
  Curr_line_num = 1;
  Indent = 0;
  Indent_offset = 0;
};

int scanner_Skip_newlines(){
  if (Inp_line[0] == 127) return 0;
  while (Eol(Inp_line[0])){
    if (fgets(Inp_line,512,Source) == NULL) {Inp_line[0] = 127; return 0;};
    Curr_line_num += 1; Curr_col = 0; Start_col = 0;
  };
};

int Next_token(){
  int Rtok, Saved_curr;
  Start_col = Curr_col;
  if (Inp_line[0] == 127){
    return 1;}
  else if (Eol(Inp_line[Curr_col])){
    if (fgets(Inp_line,512,Source) == NULL) Inp_line[0] = 127;
    Curr_line_num += 1; Curr_col = 0; Start_col = 0;
    Check_indent();
    return 2;
  };
  Curr_col = Start_col; Tok = Scan_number();
  if (Tok) return Tok;
  Curr_col = Start_col; Tok = Scan_string();
  if (Tok) return Tok;
  Curr_col = Start_col; Tok = Scan_identifier();
  if (Tok){
    Saved_curr = Curr_col; Curr_col = Start_col;
    Rtok = Scan_reserved_word();
    if (Rtok && Curr_col == Saved_curr) return Rtok;
    Curr_col = Saved_curr;
    return Tok;
  };
  Curr_col = Start_col;
  return Scan_ops_etc();
};

int Scan_identifier(){
  if (Low_let(Inp_line[Curr_col]) || Up_let(Inp_line[Curr_col])){
    if (Up_let(Inp_line[Curr_col])){
      Curr_col += 1;
    }else if (Low_let(Inp_line[Curr_col])){
      Curr_col += 1;
    }else return 0;
    do{
      if (Inp_line[Curr_col] == '_' || Low_let(Inp_line[Curr_col])){
        if (Inp_line[Curr_col] == '_'){
          Curr_col += 1;
        };
        if (!Low_let(Inp_line[Curr_col])) return 0;
        Curr_col += 1;
      }else break;
    }while(1);
  }else return 0;
 return 3;
};

int Scan_number(){
  if (Digit(Inp_line[Curr_col])){
    Curr_col += 1;
    do{
      if (Digit(Inp_line[Curr_col])){
        Curr_col += 1;
      }else break;
    }while(1);
  }else return 0;
 return 4;
};

int Scan_string(){
  if (Open_quote(Inp_line[Curr_col])){
    Curr_col += 1;
    do{
      if ((Charr(Inp_line[Curr_col]) && !Close_quote(Inp_line[Curr_col]))){
        Curr_col += 1;
      }else break;
    }while(1);
    if (!Close_quote(Inp_line[Curr_col])) return 0;
    Curr_col += 1;
  }else return 0;
 return 5;
};

int Scan_ops_etc(){
  if (Inp_line[Curr_col] == '>'){
    Curr_col += 1;
    return 7;
  }else if (Inp_line[Curr_col] == '('){
    Curr_col += 1;
    return 12;
  }else if (Inp_line[Curr_col] == '<'){
    Curr_col += 1;
    return 6;
  }else if (Inp_line[Curr_col] == '{'){
    Curr_col += 1;
    return 15;
  }else if (Inp_line[Curr_col] == '_'){
    Curr_col += 1;
    return 18;
  }else if (Inp_line[Curr_col] == '['){
    Curr_col += 1;
    return 14;
  }else if (Inp_line[Curr_col] == ']'){
    Curr_col += 1;
    return 16;
  }else if (Inp_line[Curr_col] == '='){
    Curr_col += 1;
    return 9;
  }else if (Inp_line[Curr_col] == '}'){
    Curr_col += 1;
    return 17;
  }else if (Inp_line[Curr_col] == ')'){
    Curr_col += 1;
    return 13;
  }else if (Inp_line[Curr_col] == '|'){
    Curr_col += 1;
    return 8;
  }else if (Inp_line[Curr_col] == '&'){
    Curr_col += 1;
    return 11;
  }else if (Inp_line[Curr_col] == ' '){
    Curr_col += 1;
    return 10;
  }
  Curr_col += 1;
  return 0;
};

int Scan_reserved_word(){
  return 0;
};

