Blame scanner.c

Packit d394d9
/* Copyright (C) 1995 Bjoern Beutel. */
Packit d394d9
Packit d394d9
/* Description. =============================================================*/
Packit d394d9
Packit d394d9
/* This module supports scanning (lexical analysis) of malaga source files. */
Packit d394d9
Packit d394d9
/* Includes. ================================================================*/
Packit d394d9
Packit d394d9
#include <string.h>
Packit d394d9
#include <stdio.h>
Packit d394d9
#include <errno.h>
Packit d394d9
#include <setjmp.h>
Packit d394d9
#include <glib.h>
Packit d394d9
#include "basic.h"
Packit d394d9
#include "files.h"
Packit d394d9
#include "scanner.h"
Packit d394d9
Packit d394d9
/* Constants. ===============================================================*/
Packit d394d9
Packit d394d9
/* List of all keywords and their token codes.
Packit d394d9
 * (This list must be maintained in alphabetical order.) */
Packit d394d9
static struct { string_t name; int_t code; } keywords[ NUMBER_OF_KEYWORDS ] = 
Packit d394d9
{ 
Packit d394d9
  { "accept", TOK_ACCEPT },
Packit d394d9
  { "allo_rule", TOK_ALLO_RULE },
Packit d394d9
  { "and", TOK_AND },
Packit d394d9
  { "assert", TOK_ASSERT },
Packit d394d9
  { "break", TOK_BREAK },
Packit d394d9
  { "choose", TOK_CHOOSE },
Packit d394d9
  { "combi_rule", TOK_COMBI_RULE },
Packit d394d9
  { "continue", TOK_CONTINUE },
Packit d394d9
  { "default", TOK_DEFAULT },
Packit d394d9
  { "define", TOK_DEFINE },
Packit d394d9
  { "else", TOK_ELSE },
Packit d394d9
  { "elseif", TOK_ELSEIF },
Packit d394d9
  { "end", TOK_END },
Packit d394d9
  { "end_rule", TOK_END_RULE },
Packit d394d9
  { "error", TOK_ERROR },
Packit d394d9
  { "foreach", TOK_FOREACH },
Packit d394d9
  { "greater", TOK_GREATER },
Packit d394d9
  { "greater_equal", TOK_GREATER_EQUAL },
Packit d394d9
  { "if", TOK_IF },
Packit d394d9
  { "in", TOK_IN },
Packit d394d9
  { "include", TOK_INCLUDE },
Packit d394d9
  { "initial", TOK_INITIAL },
Packit d394d9
  { "input_filter", TOK_INPUT_FILTER },
Packit d394d9
  { "less", TOK_LESS },
Packit d394d9
  { "less_equal", TOK_LESS_EQUAL },
Packit d394d9
  { "matches", TOK_MATCHES },
Packit d394d9
  { "not", TOK_NOT },
Packit d394d9
  { "or", TOK_OR },
Packit d394d9
  { "output_filter", TOK_OUTPUT_FILTER },
Packit d394d9
  { "parallel", TOK_PARALLEL },
Packit d394d9
  { "pruning_rule", TOK_PRUNING_RULE },
Packit d394d9
  { "repeat", TOK_REPEAT },
Packit d394d9
  { "require", TOK_REQUIRE },
Packit d394d9
  { "result", TOK_RESULT },
Packit d394d9
  { "return", TOK_RETURN },
Packit d394d9
  { "robust_rule", TOK_ROBUST_RULE },
Packit d394d9
  { "rules", TOK_RULES },
Packit d394d9
  { "select", TOK_SELECT },
Packit d394d9
  { "stop", TOK_STOP },
Packit d394d9
  { "subrule", TOK_SUBRULE },
Packit d394d9
  { "then", TOK_THEN },
Packit d394d9
  { "while", TOK_WHILE }
Packit d394d9
};
Packit d394d9
Packit d394d9
/* Types. ===================================================================*/
Packit d394d9
Packit d394d9
typedef struct /* A source stream for lexical analysis. */
Packit d394d9
{ 
Packit d394d9
  list_node_t *next; /* The next (including) source stream. */
Packit d394d9
  FILE *stream; /* The input stream for this include level. */
Packit d394d9
  string_t file_name; /* The name of the input file. */
Packit d394d9
  text_t *line; /* The current line. */
Packit d394d9
  string_t next_char_p; /* Pointer to the next char in LINE to be read. */
Packit d394d9
  int_t column; /* Column that has been read. */
Packit d394d9
  int_t line_number; /* Number of the line that has been read. */
Packit d394d9
  int_t next_char; /* Buffer NEXT_CHAR if this source is backed up. */
Packit d394d9
  int_t next_token; /* Buffer NEXT_TOKEN if this source is backed up. */
Packit d394d9
} source_t;
Packit d394d9
Packit d394d9
/* Global variables. ========================================================*/
Packit d394d9
Packit d394d9
int_t next_token;
Packit d394d9
string_t token_name;
Packit d394d9
char_t *token_string;
Packit d394d9
double token_number;
Packit d394d9
Packit d394d9
/* Variables. ===============================================================*/
Packit d394d9
Packit d394d9
static list_t sources; /* The list of sources, current source first. */
Packit d394d9
Packit d394d9
static string_t scanner_input;
Packit d394d9
/* If no file is included, the scanner reads its input from SCANNER_INPUT. */
Packit d394d9
Packit d394d9
static int_t next_char; /* The next unicode char to be read. */
Packit d394d9
Packit d394d9
static text_t *token_text; /* The text of the next token. */
Packit d394d9
Packit d394d9
/* Functions. ===============================================================*/
Packit d394d9
Packit d394d9
static void 
Packit d394d9
read_next_char( void )
Packit d394d9
/* Read the next char from input into NEXT_CHAR.
Packit d394d9
 * If end of input stream is reached, return EOF.
Packit d394d9
 * If no input stream is selected, read input from INPUT_BUFFER.
Packit d394d9
 * If reading from stream, update column information. */
Packit d394d9
{ 
Packit d394d9
  source_t *source;
Packit d394d9
  int_t c;
Packit d394d9
Packit d394d9
  source = (source_t *) sources.first;
Packit d394d9
  if (scanner_input != NULL) /* Read from a string. */
Packit d394d9
  { 
Packit d394d9
    if (*scanner_input == EOS)
Packit d394d9
      next_char = EOF;
Packit d394d9
    else
Packit d394d9
    {
Packit d394d9
      next_char = g_utf8_get_char( scanner_input );
Packit d394d9
      scanner_input = g_utf8_next_char( scanner_input );
Packit d394d9
    }
Packit d394d9
  } 
Packit d394d9
  else if (source != NULL) /* Read from a file. */
Packit d394d9
  { 
Packit d394d9
    /* Read a new line if current line is empty. */
Packit d394d9
    if (*source->next_char_p == EOS)
Packit d394d9
    {
Packit d394d9
      clear_text( source->line );
Packit d394d9
      do
Packit d394d9
      {
Packit d394d9
	c = getc( source->stream );
Packit d394d9
	if (c == EOS)
Packit d394d9
	  complain( "Null byte in \"%s\"", source->file_name );
Packit d394d9
	else if (c == EOF) 
Packit d394d9
	{
Packit d394d9
	  if (ferror( source->stream ))
Packit d394d9
	  {
Packit d394d9
	    complain( "Can't read from \"%s\": %s.", 
Packit d394d9
		      source->file_name, strerror( errno ) );
Packit d394d9
	  }
Packit d394d9
	  else 
Packit d394d9
	    break;
Packit d394d9
	}
Packit d394d9
	else
Packit d394d9
	  ADD_CHAR_TO_TEXT( source->line, c );
Packit d394d9
      } while (c != '\n');
Packit d394d9
      
Packit d394d9
      if (! g_utf8_validate( source->line->buffer, -1, NULL ))
Packit d394d9
	complain( "Illegal UTF-8 character in \"%s\".", source->file_name );
Packit d394d9
      source->next_char_p = source->line->buffer;
Packit d394d9
    }
Packit d394d9
Packit d394d9
    if (*source->next_char_p == EOS)
Packit d394d9
      next_char = EOF;
Packit d394d9
    else
Packit d394d9
    {
Packit d394d9
      /* Get next char from current line. */
Packit d394d9
      next_char = g_utf8_get_char( source->next_char_p );
Packit d394d9
      source->next_char_p = g_utf8_next_char( source->next_char_p );
Packit d394d9
      
Packit d394d9
      /* Update line and column information. */
Packit d394d9
      if (next_char == '\t') 
Packit d394d9
	source->column = (source->column + 8) & ~7;
Packit d394d9
      else if (next_char == '\n') 
Packit d394d9
      { 
Packit d394d9
	source->column = 0;
Packit d394d9
	source->line_number++;
Packit d394d9
      }
Packit d394d9
      else if (next_char == '\r')
Packit d394d9
	source->column = 0;
Packit d394d9
      else if (next_char != EOF) 
Packit d394d9
	source->column++;
Packit d394d9
    }
Packit d394d9
  } 
Packit d394d9
  else 
Packit d394d9
    next_char = EOF;
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
string_t 
Packit d394d9
current_file_name( void )
Packit d394d9
/* Return the name of the file reading from or NULL. */
Packit d394d9
{
Packit d394d9
  source_t *source;
Packit d394d9
Packit d394d9
  source = (source_t *) sources.first;
Packit d394d9
  if (source == NULL) 
Packit d394d9
    return NULL;
Packit d394d9
  return source->file_name;
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
int_t 
Packit d394d9
current_line_number( void )
Packit d394d9
/* Return the line number where the last char has been read or -1. */
Packit d394d9
{
Packit d394d9
  source_t *source;
Packit d394d9
Packit d394d9
  source = (source_t *) sources.first;
Packit d394d9
  if (source == NULL) 
Packit d394d9
    return -1;
Packit d394d9
  return source->line_number;
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
int_t 
Packit d394d9
current_column( void )
Packit d394d9
/* Return the column where the last char has been read or -1. */
Packit d394d9
{
Packit d394d9
  source_t *source;
Packit d394d9
Packit d394d9
  source = (source_t *) sources.first;
Packit d394d9
  if (source == NULL) 
Packit d394d9
    return -1;
Packit d394d9
  if (source->column == 0) 
Packit d394d9
    return 0;
Packit d394d9
  return source->column - 1; /* Let columns start with 0. */
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
void 
Packit d394d9
set_scanner_input( string_t input )
Packit d394d9
/* Make the scanner use INPUT as scanner input 
Packit d394d9
 * until "set_scanner_input( NULL )" is called.
Packit d394d9
 * INPUT must remain valid until then. */
Packit d394d9
{
Packit d394d9
  source_t *source;
Packit d394d9
Packit d394d9
  source = (source_t *) sources.first;
Packit d394d9
  scanner_input = input;
Packit d394d9
  if (input != NULL) 
Packit d394d9
  { 
Packit d394d9
    if (source != NULL) 
Packit d394d9
    { 
Packit d394d9
      source->next_char = next_char;
Packit d394d9
      source->next_token = next_token;
Packit d394d9
    }
Packit d394d9
    read_next_char();
Packit d394d9
    read_next_token();
Packit d394d9
  } 
Packit d394d9
  else if (source != NULL) 
Packit d394d9
  { 
Packit d394d9
    next_char = source->next_char;
Packit d394d9
    next_token = source->next_token;
Packit d394d9
  }
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
void 
Packit d394d9
begin_include( string_t file_name )
Packit d394d9
/* Open a new level of inclusion and read tokens from file FILE_NAME. */
Packit d394d9
{
Packit d394d9
  FILE *stream;
Packit d394d9
  source_t *source;
Packit d394d9
Packit d394d9
  source = (source_t *) sources.first;
Packit d394d9
  stream = open_stream( file_name, "r" );
Packit d394d9
  /* Next char of old source should be read later. */
Packit d394d9
  if (source != NULL) 
Packit d394d9
  { 
Packit d394d9
    source->next_char = next_char;
Packit d394d9
    source->next_token = next_token;
Packit d394d9
  }
Packit d394d9
  /* Create new source description. */
Packit d394d9
  source = new_node( &sources, sizeof( source_t ), LIST_START );
Packit d394d9
  source->line = new_text();
Packit d394d9
  source->next_char_p = source->line->buffer;
Packit d394d9
  source->file_name = file_name;
Packit d394d9
  source->line_number = 1;
Packit d394d9
  source->column = 0;
Packit d394d9
  source->stream = stream;
Packit d394d9
  read_next_char();
Packit d394d9
  read_next_token();
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
void 
Packit d394d9
end_include( void )
Packit d394d9
/* Stop reading from current source stream and read from former stream. */
Packit d394d9
{
Packit d394d9
  source_t *source;
Packit d394d9
Packit d394d9
  source = (source_t *) sources.first;
Packit d394d9
  close_stream( &source->stream, source->file_name );
Packit d394d9
  free_text( &source->line );
Packit d394d9
  free_first_node( &sources );
Packit d394d9
  if (sources.first != NULL) 
Packit d394d9
  { 
Packit d394d9
    source = (source_t *) sources.first;
Packit d394d9
    next_char = source->next_char;
Packit d394d9
    next_token = source->next_token;
Packit d394d9
  }
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
void 
Packit d394d9
end_includes( void )
Packit d394d9
/* Stop reading from all nested source streams. */
Packit d394d9
{
Packit d394d9
  while (sources.first != NULL) 
Packit d394d9
    end_include();
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
void 
Packit d394d9
init_scanner( void )
Packit d394d9
/* Initialise the scanner. */
Packit d394d9
{
Packit d394d9
  token_text = new_text();
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
void 
Packit d394d9
terminate_scanner( void )
Packit d394d9
/* Terminate the scanner, even when it's scanning. */
Packit d394d9
{
Packit d394d9
  source_t *source;
Packit d394d9
Packit d394d9
  scanner_input = NULL;
Packit d394d9
  FOREACH_FREE( source, sources ) 
Packit d394d9
  {
Packit d394d9
    close_stream( &source->stream, NULL );
Packit d394d9
    free_text( &source->line );
Packit d394d9
  }
Packit d394d9
  token_name = NULL;
Packit d394d9
  free_text( &token_text );
Packit d394d9
  free_mem( &token_string );
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void 
Packit d394d9
read_name( void )
Packit d394d9
/* Read rule name, variable, or keyword into TOKEN_NAME. */
Packit d394d9
{
Packit d394d9
  token_name = NULL;
Packit d394d9
  clear_text( token_text );
Packit d394d9
Packit d394d9
  while (next_char != EOF
Packit d394d9
         && (g_unichar_isalnum( next_char )
Packit d394d9
	     || next_char == '_' || next_char == '&' || next_char == '|'))
Packit d394d9
  { 
Packit d394d9
    add_unichar_to_text( token_text, next_char );
Packit d394d9
    read_next_char();
Packit d394d9
  }
Packit d394d9
Packit d394d9
  token_name = token_text->buffer;
Packit d394d9
  if (*token_name == EOS) 
Packit d394d9
    complain( "Illegal character in name." );
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static int_t 
Packit d394d9
keyword_code( string_t name )
Packit d394d9
/* Look up NAME in the keyword table and return its token value.
Packit d394d9
 * If NAME is no keyword, return TOK_IDENT. */
Packit d394d9
{
Packit d394d9
  int_t lower, upper, middle, result;
Packit d394d9
Packit d394d9
  /* We do a binary search on the keywords.
Packit d394d9
   * A keyword must be in the range of keywords[ lower..upper ]. */
Packit d394d9
  lower = 0;
Packit d394d9
  upper = NUMBER_OF_KEYWORDS - 1;
Packit d394d9
  while (lower <= upper) 
Packit d394d9
  { 
Packit d394d9
    middle = (lower + upper) / 2;
Packit d394d9
    result = strcmp_no_case( name, keywords[ middle ].name );
Packit d394d9
    if (result < 0) 
Packit d394d9
      upper = middle - 1;
Packit d394d9
    else if (result > 0) 
Packit d394d9
      lower = middle + 1;
Packit d394d9
    else 
Packit d394d9
      return keywords[ middle ].code;
Packit d394d9
  }
Packit d394d9
  return TOK_IDENT;
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void 
Packit d394d9
read_number( void )
Packit d394d9
/* Read a floating point number. Save its value in TOKEN_NUMBER. */
Packit d394d9
{
Packit d394d9
  token_name = NULL;
Packit d394d9
  clear_text( token_text );
Packit d394d9
Packit d394d9
  while (next_char >= '0' && next_char <= '9') 
Packit d394d9
  { 
Packit d394d9
    add_char_to_text( token_text, next_char );
Packit d394d9
    read_next_char();
Packit d394d9
  }
Packit d394d9
  if (next_char == 'l' || next_char == 'L') 
Packit d394d9
    read_next_char();
Packit d394d9
  else if (next_char == 'r' || next_char == 'R') 
Packit d394d9
  { 
Packit d394d9
    insert_char_in_text( token_text, '-', 0 );
Packit d394d9
    read_next_char();
Packit d394d9
  } 
Packit d394d9
  else 
Packit d394d9
  { 
Packit d394d9
    if (next_char == '.') 
Packit d394d9
    { 
Packit d394d9
      add_char_to_text( token_text, next_char );
Packit d394d9
      read_next_char();
Packit d394d9
      if (next_char < '0' || next_char >'9') 
Packit d394d9
	complain( "Missing digits after \".\"." );
Packit d394d9
      while (next_char >= '0' && next_char <= '9') 
Packit d394d9
      { 
Packit d394d9
	add_char_to_text( token_text, next_char );
Packit d394d9
        read_next_char();
Packit d394d9
      }
Packit d394d9
    }
Packit d394d9
    if (next_char == 'E' || next_char == 'e') 
Packit d394d9
    { /* Read an exponent. */
Packit d394d9
      add_char_to_text( token_text, next_char );
Packit d394d9
      read_next_char();
Packit d394d9
      if (next_char == '-' || next_char == '+') 
Packit d394d9
      { 
Packit d394d9
	add_char_to_text( token_text, next_char );
Packit d394d9
        read_next_char();
Packit d394d9
      }
Packit d394d9
      if (next_char < '0' || next_char > '9') 
Packit d394d9
	complain( "Missing exponent." );
Packit d394d9
      while (next_char >= '0' && next_char <= '9') 
Packit d394d9
      { 
Packit d394d9
	add_char_to_text( token_text, next_char );
Packit d394d9
        read_next_char();
Packit d394d9
      }  
Packit d394d9
    }
Packit d394d9
  }
Packit d394d9
  if (sscanf( token_text->buffer, "%lf", &token_number ) != 1) 
Packit d394d9
    complain( "Illegal number." );
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void 
Packit d394d9
read_string( void )
Packit d394d9
/* Read a string. Save its value in TOKEN_STRING. */
Packit d394d9
{
Packit d394d9
  int_t i;
Packit d394d9
  u_int_t code;
Packit d394d9
Packit d394d9
  token_name = NULL;
Packit d394d9
  clear_text( token_text );
Packit d394d9
  read_next_char(); /* Overread beginning '"'. */
Packit d394d9
  while (next_char != '\"') 
Packit d394d9
  { 
Packit d394d9
    if (next_char == EOF || next_char == '\n') 
Packit d394d9
      complain( "Unterminated string at end of line." );
Packit d394d9
    if (next_char != '\\') 
Packit d394d9
    {
Packit d394d9
      add_unichar_to_text( token_text, next_char );
Packit d394d9
      read_next_char();
Packit d394d9
    }
Packit d394d9
    else
Packit d394d9
    { 
Packit d394d9
      read_next_char();
Packit d394d9
      if (next_char == '\\' || next_char == '\"')
Packit d394d9
      {
Packit d394d9
	add_char_to_text( token_text, next_char );
Packit d394d9
	read_next_char();
Packit d394d9
      }
Packit d394d9
      else if (next_char >= '0'  && next_char <= '7')
Packit d394d9
      { 
Packit d394d9
	code = 0;
Packit d394d9
	for (i = 0; i < 3; i++) 
Packit d394d9
	{ 
Packit d394d9
	  if (next_char >= '0' && next_char <= '7')
Packit d394d9
	    code = 8 * code + (next_char - '0');
Packit d394d9
	  else 
Packit d394d9
	    complain( "Escape sequence must have 3 octal digits." );
Packit d394d9
	  read_next_char();
Packit d394d9
	}
Packit d394d9
	if (! g_unichar_validate( code ))
Packit d394d9
	  complain( "Escape sequence defines invalid character." );
Packit d394d9
	add_unichar_to_text( token_text, code );
Packit d394d9
      }
Packit d394d9
      else 
Packit d394d9
	complain( "Illegal escape sequence in string." );
Packit d394d9
    }
Packit d394d9
  }
Packit d394d9
  read_next_char(); /* Read over final '"'. */
Packit d394d9
  free_mem( &token_string ); /* Free old token string. */
Packit d394d9
  token_string = new_string( token_text->buffer, NULL );
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
void 
Packit d394d9
read_next_token( void )
Packit d394d9
/* Read the next token from current source into NEXT_TOKEN.
Packit d394d9
 * If end of input stream is reached, return EOF. */
Packit d394d9
{
Packit d394d9
  /* Read chars until a token has been recognised. */
Packit d394d9
  while (TRUE) 
Packit d394d9
  { 
Packit d394d9
    switch (next_char) 
Packit d394d9
    {
Packit d394d9
    case EOF:
Packit d394d9
      next_token = EOF;
Packit d394d9
      return;
Packit d394d9
    case ' ': 
Packit d394d9
    case '\t': 
Packit d394d9
    case '\n': /* Read over whitespace. */
Packit d394d9
      read_next_char();
Packit d394d9
      break;
Packit d394d9
    case '\r':
Packit d394d9
      read_next_char();
Packit d394d9
      if (next_char != '\n')
Packit d394d9
	complain( "Carriage return without line feed." );
Packit d394d9
      read_next_char();
Packit d394d9
      break;
Packit d394d9
    case '#': /* Read over a comment. */
Packit d394d9
      do 
Packit d394d9
      { 
Packit d394d9
	read_next_char(); 
Packit d394d9
      } while (next_char != '\n' && next_char != EOF);
Packit d394d9
      break;
Packit d394d9
    case '\"': /* Read a string. */
Packit d394d9
      read_string();
Packit d394d9
      next_token = TOK_STRING;
Packit d394d9
      return;
Packit d394d9
    case ':': /* Read a ":", ":=", ":=+", ":=-", ":=*", ":=/". */
Packit d394d9
      read_next_char();
Packit d394d9
      if (next_char == '=') 
Packit d394d9
      { 
Packit d394d9
	read_next_char();
Packit d394d9
        if (next_char == '+') 
Packit d394d9
	{ 
Packit d394d9
	  next_token = TOK_ASSIGN_PLUS;
Packit d394d9
	  read_next_char();
Packit d394d9
        } 
Packit d394d9
	else if (next_char == '-') 
Packit d394d9
	{ 
Packit d394d9
	  next_token = TOK_ASSIGN_MINUS;
Packit d394d9
          read_next_char();
Packit d394d9
        }
Packit d394d9
	else if (next_char == '*') 
Packit d394d9
	{ 
Packit d394d9
	  next_token = TOK_ASSIGN_ASTERISK;
Packit d394d9
          read_next_char();
Packit d394d9
        } 
Packit d394d9
	else if (next_char == '/') 
Packit d394d9
	{ 
Packit d394d9
	  next_token = TOK_ASSIGN_SLASH;
Packit d394d9
          read_next_char();
Packit d394d9
        } 
Packit d394d9
	else 
Packit d394d9
	  next_token = TOK_ASSIGN;
Packit d394d9
      } 
Packit d394d9
      else 
Packit d394d9
	next_token = ':';
Packit d394d9
      return;
Packit d394d9
    case '/': /* Read a "/", a "/=" or a "/~". */
Packit d394d9
      read_next_char();
Packit d394d9
      if (next_char == '=') 
Packit d394d9
      { 
Packit d394d9
	next_token = TOK_NOT_EQUAL;
Packit d394d9
        read_next_char();
Packit d394d9
      } 
Packit d394d9
      else if (next_char == '~') 
Packit d394d9
      { 
Packit d394d9
        next_token = TOK_NOT_CONGRUENT;
Packit d394d9
        read_next_char();
Packit d394d9
      } 
Packit d394d9
      else 
Packit d394d9
	next_token = '/';
Packit d394d9
      return;
Packit d394d9
    case '0': case '1': case '2': case '3': case '4':
Packit d394d9
    case '5': case '6': case '7': case '8': case '9': 
Packit d394d9
      /* Read a number. */
Packit d394d9
      read_number();
Packit d394d9
      next_token = TOK_NUMBER;
Packit d394d9
      return;
Packit d394d9
    case '$':
Packit d394d9
      read_next_char();
Packit d394d9
      read_name();
Packit d394d9
      next_token = TOK_VARIABLE;
Packit d394d9
      return;
Packit d394d9
    case '@':
Packit d394d9
      read_next_char();
Packit d394d9
      read_name();
Packit d394d9
      next_token = TOK_CONSTANT;
Packit d394d9
      return;
Packit d394d9
    default: 
Packit d394d9
    if (g_unichar_isalpha( next_char ) 
Packit d394d9
        || next_char == '_' || next_char == '&' || next_char == '|') 
Packit d394d9
      { 
Packit d394d9
	read_name();
Packit d394d9
        next_token = keyword_code( token_name );
Packit d394d9
        return;
Packit d394d9
      } 
Packit d394d9
      else 
Packit d394d9
      { 
Packit d394d9
	next_token = next_char;
Packit d394d9
        read_next_char();
Packit d394d9
        return;
Packit d394d9
      }
Packit d394d9
    }
Packit d394d9
  }
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
string_t 
Packit d394d9
token_as_text( int_t token )
Packit d394d9
/* Return TOKEN as a string readable for humans.
Packit d394d9
 * The string must be freed after use. */
Packit d394d9
{
Packit d394d9
  int_t i;
Packit d394d9
  char token_buffer[2];
Packit d394d9
Packit d394d9
  /* Look if TOKEN is a keyword. */
Packit d394d9
  for (i = 0; i < NUMBER_OF_KEYWORDS; i++) 
Packit d394d9
  { 
Packit d394d9
    if (keywords[i].code == token) 
Packit d394d9
      return concat_strings( "\"", keywords[i].name, "\"", NULL );
Packit d394d9
  }
Packit d394d9
  
Packit d394d9
  switch (token) 
Packit d394d9
  {
Packit d394d9
  case EOF: 
Packit d394d9
    return new_string( "end of input", NULL ); 
Packit d394d9
  case TOK_STRING: 
Packit d394d9
    return new_string( "string", NULL );
Packit d394d9
  case TOK_IDENT: 
Packit d394d9
    return new_string( "identifier", NULL );
Packit d394d9
  case TOK_VARIABLE: 
Packit d394d9
    return new_string( "variable", NULL );
Packit d394d9
  case TOK_CONSTANT: 
Packit d394d9
    return new_string( "constant", NULL );
Packit d394d9
  case TOK_NUMBER: 
Packit d394d9
    return new_string( "number", NULL );
Packit d394d9
  case TOK_ASSIGN: 
Packit d394d9
    return new_string_readable( ":=", NULL );
Packit d394d9
  case TOK_ASSIGN_PLUS: 
Packit d394d9
    return new_string_readable( ":=+", NULL );
Packit d394d9
  case TOK_ASSIGN_MINUS: 
Packit d394d9
    return new_string_readable( ":=-", NULL );
Packit d394d9
  case TOK_ASSIGN_ASTERISK: 
Packit d394d9
    return new_string_readable( ":=*", NULL );
Packit d394d9
  case TOK_ASSIGN_SLASH: 
Packit d394d9
    return new_string_readable( ":=/", NULL );
Packit d394d9
  case TOK_NOT_EQUAL: 
Packit d394d9
    return new_string_readable( "/=", NULL );
Packit d394d9
  case TOK_NOT_CONGRUENT: 
Packit d394d9
    return new_string_readable( "/~", NULL );
Packit d394d9
  default:
Packit d394d9
    token_buffer[0] = token;
Packit d394d9
    token_buffer[1] = EOS;
Packit d394d9
    return new_string_readable( token_buffer, NULL );
Packit d394d9
  }
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
void 
Packit d394d9
test_token( int_t token )
Packit d394d9
/* Test if TOKEN is the next token. If it's not, report an error. */
Packit d394d9
{
Packit d394d9
  if (next_token != token) 
Packit d394d9
  { 
Packit d394d9
    complain( "Expected %s, not %s.", 
Packit d394d9
	      token_as_text( token ), token_as_text( next_token ) );
Packit d394d9
  }
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
void 
Packit d394d9
parse_token( int_t token )
Packit d394d9
/* Test if TOKEN is the next token and read next token. */
Packit d394d9
{
Packit d394d9
  test_token( token );
Packit d394d9
  read_next_token();
Packit d394d9
}
Packit d394d9
Packit d394d9
/* End of file. =============================================================*/