


























FILE *input_file[MAX_INCLUDES];
char *input_name[MAX_INCLUDES];
int   input_offset[MAX_INCLUDES];
int   input_line[MAX_INCLUDES];
int   input_column[MAX_INCLUDES];
int   input_last_line_last_column[MAX_INCLUDES];
int   input_level = -1;

static int debug_takeon = 0;


static void takeon(FILE *f) {

  
  static int def_phrase = FALSE;    
                                    
                                    
  static int def_alts = FALSE;      
                                    
                                    
  static int def_type = 0;          
                                    
  
  static int sym = unassigned;

  
  static int specialbit = 0; 
                             
                             
                             
                             
  static int alt_count = 1;
  static int alt_count_index = 0;

  static int phrase_count = 0;
  static int phrase_count_index = 0;

  _initcode(initcode_nextfree = 0) = '\0';
  
  for (;;) {
    sym = nonspace();

    switch (sym) {  
                    

    case 'I': 
    case 'O': 
    case 'B': 
    case 'P': 
    case 'C': 

      if (def_alts || def_phrase) {
        fprintf(stderr,
                "ERROR: Phrase <%ls> was not finalised before starting a new one."
                "  Missing semi-colon!\n", String(current_def_phrasename));
        exit(EXIT_FAILURE);
      }
      
      def_phrase = TRUE; def_alts = FALSE; def_type = sym;

      

      break;

      
    case '<': 
              
      if (def_phrase) {
        
        phrase_count = 0;
        current_def_phrasename = upto(L'>');
        switch (def_type) {
        case 'O': 
                  break;
        case 'B': _bip_phrasename(current_def_bipno = NEXT_FREE_BIPNO++) = current_def_phrasename;
                  if (NEXT_FREE_BIPNO >= NUM_BIPS) NUM_BIPS = NEXT_FREE_BIPNO;
                  break;
        case 'P': _phrasename(current_def_simple_phraseno = NEXT_FREE_SIMPLE_PHRASENO++) = current_def_phrasename;
                  _ast_code(current_def_simple_phraseno) = -1;
                  if (NEXT_FREE_SIMPLE_PHRASENO >= NUM_SIMPLE_PHRASES) NUM_SIMPLE_PHRASES = NEXT_FREE_SIMPLE_PHRASENO;
                  break;
        case 'C': _semantic_phrasename(current_def_semantic_phraseno = NEXT_FREE_SEMANTIC_PHRASENO++) = current_def_phrasename;
                  if (NEXT_FREE_SEMANTIC_PHRASENO >= NUM_SEMANTIC_PHRASES) NUM_SEMANTIC_PHRASES = NEXT_FREE_SEMANTIC_PHRASENO;
                  break;
        case 'I': if (nonspace() != ';') fatal(';');

                 
           
                  input_offset[input_level] = file_offset;
                  input_line[input_level] = source_line;
                  input_column[input_level] = source_column;
                  input_last_line_last_column[input_level] = last_line_last_column;

                  input_level += 1;
                  if (input_level >= MAX_INCLUDES) {
                    fprintf(stderr, "Error: I<include> files are too deeply nested:\n");
                    while (--input_level >= 0) {
                      fprintf(stderr, "       %s\n", input_name[input_level]);
                    }
                    exit(1);
                  }
                  char string[1024];
                  int length = wcstombs(string, String(current_def_phrasename), 1023); 
                  (void)length;
                  input_name[input_level] = strdup(string);
                  input_file[input_level] = fopen(input_name[input_level], "r");
                  if (input_file[input_level] == NULL) {
                    fprintf(stderr, "Error: could not open include file: %s - %s\n", input_name[input_level], strerror(errno));
                    exit(1);
                  }
                  
                  
                  def_phrase = FALSE;
                  def_alts = FALSE;
                  def_type = 0;
                  break;
        }
        break;
        
        
      } else {
        
        int i;
        
        phrase_count += 1; 
        _gram(phrase_count_index) = phrase_count | COUNT_OF_PHRASES;
        if (phrase_count > LARGEST_ALT) LARGEST_ALT = phrase_count;

        sym = next_wide_char();  
        if (sym == '?') {
          specialbit = GUARD_PHRASE;
          
	} else if (sym == '!') { 
          
          
          specialbit = NEGATED_PHRASE;
	} else {
	  unget_wide_char(sym, input_file[input_level]);
          specialbit = 0;
	}

        current_use_phrasename = upto(L'>'); 
        
        if (pass == 0) {
          _gram(NEXT_FREE_GRAMMAR_SLOTNO++) = 0; 
          break;
        }

        
        for (i = 0; i < NUM_BIPS; i++) {
          if (wcscmp(String(bip_phrasename(i)), String(current_use_phrasename)) == 0) {
            _gram(NEXT_FREE_GRAMMAR_SLOTNO++) = i
                                              | specialbit 
                                              | BIP_TYPE;
            break;
          }
        }
        
        
        
        if (i < NUM_BIPS) break;
        
        for (i = 0; i < NUM_SIMPLE_PHRASES; i++) {
          if (wcscmp(String(phrasename(i)), String(current_use_phrasename)) == 0) {
            _gram(NEXT_FREE_GRAMMAR_SLOTNO++) = i
                                              | specialbit 
                                              | PHRASE_TYPE;
            break;
          }
        }
        if (i < NUM_SIMPLE_PHRASES) break;
        
        for (i = 0; i < NUM_SEMANTIC_PHRASES; i++) {
          if (wcscmp(String(semantic_phrasename(i)), String(current_use_phrasename)) == 0) {
            _gram(NEXT_FREE_GRAMMAR_SLOTNO++) = i
                                              | specialbit 
                                              | SEMANTIC_TYPE;
            break;
          }
        }
        if (i < NUM_SEMANTIC_PHRASES) break;

        fprintf(stderr, "* Error: P<%ls> not defined.\n", String(current_use_phrasename));
        exit(EXIT_FAILURE);
        
      }
      
      break;

    case '=': 
      
      
      
      
      
      
      
      

      if (!def_phrase) {
        fatal(0); 
      }
      switch (def_type) {

      case 'O': 
        {
          int number;
          sym = nonspace();
          if (!isdigit(sym)) fatal('0');
          number = sym-'0';
          sym = get_wide_char(input_file[input_level]);
          if (isdigit(sym)) {
            number = number*10 + (sym-'0');
          } else {
            unget_wide_char(sym, input_file[input_level]);
          }
          if (pass == 1) { 
            
            
            
            
          }
          break;
        }
        
      case 'B': 
        {
          

          
          
          
          
          
          int c, number = nonspace();
          if (!isdigit(number)) fatal('0');
          number -= '0';
          c = get_wide_char(input_file[input_level]);
          if (isdigit(c)) {
            number = number*10 + (c-'0');
          } else {
            unget_wide_char(c, input_file[input_level]);
          }
  
          _bip_phrasename(current_def_bipno) = current_def_phrasename;
          _bip_map(current_def_bipno) = number;
          if (nonspace() != ';') fatal(';'); 
          def_phrase = FALSE;
  
          
          
          
          
          break;    
        }

      case 'C': 
        {

          
          if (nonspace() != '{') {
            fatal('{'); 
          }

          
          _semantic_code(current_def_semantic_phraseno) = c_code_block();

          if (nonspace() != ';') fatal(';'); 
          def_phrase = FALSE;

          
          
          break;  
        }

      case 'P': 
        { 

          _sequential_phrase_no_to_grammar_index(current_def_simple_phraseno) = NEXT_FREE_GRAMMAR_SLOTNO;  
          
          _grammar_index_to_sequential_phrase_number(NEXT_FREE_GRAMMAR_SLOTNO) = current_def_simple_phraseno;

          def_phrase = FALSE; def_alts = TRUE;

          alt_count = 1;
          alt_count_index = NEXT_FREE_GRAMMAR_SLOTNO++;    
          _gram(alt_count_index) = alt_count | COUNT_OF_ALTS;

          
          phrase_count_index = NEXT_FREE_GRAMMAR_SLOTNO++; 
          _gram(phrase_count_index) = phrase_count | COUNT_OF_PHRASES;          
          
          
          
          break;  
        }
        
      } 
      break; 

    case '\'': 
      if (def_phrase) {
        fprintf(stderr, "Line %d: P'...' is not allowed.  'Literals' are"
                " only allowed on the RHS of the '='.\n", source_line);
        exit(EXIT_FAILURE);
      } else {
        STRINGINDEX string = upto(L'\'');

        
        

        
        
      
        {
          wchar_t *s = String(string);
          while (*s != '\0') {
            if ((((*s)&~255) != 0) && (((*s)&~255) != 0xFFFFFF00)) {
              
              
              fprintf(stderr, "Warning: Unicode char constant truncated: %lc\n", (wint_t)(*s));
            }
            _gram(NEXT_FREE_GRAMMAR_SLOTNO++) = CHAR_TYPE | WHITESPACE_ALLOWED | ((*s++)&255); 
            phrase_count += 1;
          }
        }
        _gram(phrase_count_index) = phrase_count | COUNT_OF_PHRASES;
        if (phrase_count > LARGEST_ALT) LARGEST_ALT = phrase_count;
        break;
      }
      
    case '"': 
      if (def_phrase) {
        fprintf(stderr, "Line %d: P\"...\" is not allowed.  \"Keywords\" are only allowed on the RHS of the '='.\n", source_line);
        exit(EXIT_FAILURE);
      } else {
        STRINGINDEX keyword = upto(L'"');

        phrase_count += 1;
        _gram(phrase_count_index) = phrase_count;
        if (phrase_count > LARGEST_ALT) LARGEST_ALT = phrase_count;
        
        
        _gram(NEXT_FREE_GRAMMAR_SLOTNO++) = WHITESPACE_ALLOWED | keyword_code(keyword) ;

        break;
      }
      
    case L'«': 
      if (def_phrase) {
        fprintf(stderr, "Line %d: P«...» is not allowed.  Regular «expressions» are"
                        " only allowed on the RHS of the '='\n", source_line);
        exit(EXIT_FAILURE);
      } else {
        
        STRINGINDEX regex, anchored_regexp = Str_nextfree++;
        _StringPool(anchored_regexp) = '^';
        regex = upto(L'»'); 
        assert(regex == anchored_regexp+1);
        
        phrase_count += 1;
        _gram(phrase_count_index) = phrase_count | COUNT_OF_PHRASES;
        if (phrase_count > LARGEST_ALT) LARGEST_ALT = phrase_count;
        
        _gram(NEXT_FREE_GRAMMAR_SLOTNO++) = regexp_code(anchored_regexp) | WHITESPACE_ALLOWED;
      }
      break;
      
    case '|': 
    case ',': 
      
      _gram(phrase_count_index) = phrase_count | COUNT_OF_PHRASES; 
      if (phrase_count > LARGEST_ALT) LARGEST_ALT = phrase_count;

      
      alt_count += 1;
      _gram(alt_count_index) = alt_count | COUNT_OF_ALTS;

      phrase_count = 0;
      phrase_count_index = NEXT_FREE_GRAMMAR_SLOTNO++;
      _gram(phrase_count_index) = phrase_count;

      break;

    case '{': 
      {

        if (!def_alts) {

          
          

          
          
          
          
          int level = 0;
          
          for (;;) {
            sym = next_wide_char();

            if (sym == '/') {                   
              _initcode(initcode_nextfree++) = sym;
              sym = next_wide_char();
              if (sym == '/') {
                
                for (;;) {
                  _initcode(initcode_nextfree++) = sym;
                  sym = next_wide_char();
                  if (sym == '\n') break;
                }
              }
              
              
            }

            if (sym == '{') level += 1;
            if ((sym == '}') && (level == 0)) break;
            if (sym == '}') level -= 1;
            _initcode(initcode_nextfree++) = sym;
          }
          _initcode(initcode_nextfree) = '\0';
          break;
          
        } else {
          
          if (def_type != 'P') {
            fatal('{');
          }
          
          
          
          
          _ast_code(current_def_simple_phraseno) = c_code_block();

          if (nonspace() != ';') fatal(';'); 
        }

      }
      
      
    case ';': 
              

      
      
      
      
      

      
      

      
      _gram(alt_count_index)    = alt_count    | COUNT_OF_ALTS;
      _gram(phrase_count_index) = phrase_count | COUNT_OF_PHRASES;
      
      
      alt_count = 0; phrase_count = 0;
      def_phrase = FALSE; def_alts = FALSE;
      current_def_phrasename = unassigned;

      if (NEXT_FREE_GRAMMAR_SLOTNO >= NUM_GRAMMAR) NUM_GRAMMAR = NEXT_FREE_GRAMMAR_SLOTNO;
        
      break;

    case 'E': 
      return;

    case '#': 
      {       
        
        for (;;) {
          sym = next_wide_char();
          _StringPool(Str_nextfree++) = sym;
          if (sym == '\n') break;
        }
        _StringPool(Str_nextfree++) = '\0';
      }
      break;

    default:
      fprintf(stderr, "* Error: unexpected character '%lc' in %s\n", sym, input_name[input_level]);
      fatal(0);
      
    } 

  } 


}

int main(int argc, char **argv) {
   (void) setlocale(LC_ALL, "");
  FILE *sink = fopen("/dev/null", "w");

  debug_flex = 0;

  if ((sizeof(wchar_t) < 4) || (sizeof(wint_t) < 4)) {
    fprintf(stderr, "takeon: wchar_t or wint_t size is %d bytes "
                    "- please recompile with a real compiler.\n",
            MinINT(sizeof(wchar_t),sizeof(wint_t)));
    exit(EXIT_FAILURE);
  }
  
  
  
  

  if ((argc >= 2) && (strcmp(argv[1], "-d")==0)) {
    argc -= 1; argv += 1; debug_takeon = TRUE;
  }

  if (argc != 2) {
    fprintf(stderr, "syntax: takeon [-d] compiler.g\n");
    exit(EXIT_FAILURE);
  }

  
  
  
  for (pass = 0; pass <= 1; pass++) {

    FILE *grammar; 
    char *grammarfn = NULL;
    

    grammar = fopen(grammarfn=argv[1], "r");
    if (grammar == NULL) {
      int err = errno;
      fprintf(stderr, "takeon: %s - %s\n", strerror(err), argv[1]);
      exit(err); 
    }

    input_level = 0;
    input_file[input_level] = grammar;
    input_name[input_level] = grammarfn;
    
    
    
    
    
    NEXT_FREE_BIPNO = 0;
    NEXT_FREE_SIMPLE_PHRASENO = 0;
    NEXT_FREE_SEMANTIC_PHRASENO = 0;

    NEXT_FREE_GRAMMAR_SLOTNO = 0;
    
    
    
    LARGEST_ALT = 0;
    BIP_BASE = 0;
    PHRASE_BASE = 0;
    SEMANTIC_BASE = 0;
    AST_BASE = 0;
    
    takeon(stderr); 

    if (input_level != 0) {
      fprintf(stderr, "Error: input_level = %d at end of grammar.\n", input_level);
    }
    fclose(input_file[input_level]); grammar = NULL; 
  }

  dump_tables(stdout); fflush(stdout);
   
    
  check_all_phrases();  


  fclose(sink);
  exit(EXIT_SUCCESS); return(EXIT_FAILURE);
}


