/**************************************************************************
 * scenery.l -- Lexical Analyzer for scenery files
 *
 * Written by Curtis Olson, started May 1997.
 *
 * Copyright (C) 1997  Curtis L. Olson  - curt@infoplane.com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * NOTE: Compiles with flex and gcc.
 *
 * $Id$
 **************************************************************************/


/* C Pass Through */
%{
    #include <stdio.h>
    #include "parser.h"

    int line_num = 1;
    char c;

    /* custom print routine */
    static int scanner_debug = 0;

    /* Routines to manage a stack of nested input buffers (for
       processing the #include directive */
    #define MAX_INCLUDE_DEPTH 10
    static YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
    static int include_stack_ptr = 0;

    int push_input_stream ( char *input ) { 
	FILE *yyin_save;
        if ( include_stack_ptr >= MAX_INCLUDE_DEPTH ) {
	    fprintf( stderr, "Scanner says:  Includes nested too deeply\n" );
	    return(0);
	}

	/* save yyin in case the following fails */
	yyin_save = yyin;

	yyin = fopen( input, "r" );
	if ( ! yyin ) {
	    fprintf( stderr, "Scanner says:  cannot open '%s'\n", input );

	    /* The failed attempt destroyed yyin, so restore it */
	    yyin = yyin_save;

	    return(0);
	}
 
	include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
     	yy_switch_to_buffer( yy_create_buffer(yyin, YY_BUF_SIZE) );

	return(1);
    }

    int pop_input_stream () { 
	if ( --include_stack_ptr < 1 ) {
	    /* end of last input stream */
	    return(0);
	} else {
	    /* end of current input stream, restore previous and continue */
	    yy_delete_buffer( YY_CURRENT_BUFFER );
	    yy_switch_to_buffer( include_stack[include_stack_ptr] );
	    return(1);
	}
    }
%}


/* Definitions */
letter		[A-Za-z]
digit		[0-9]
connecter       [_-]
ident		{letter}({letter}|{digit}|{connecter})*

integer		[+-]?{digit}+

plain_real	{integer}"."{integer}
short_exp_real  {integer}[Ee][+-]?{integer}
exp_real	{plain_real}[Ee][+-]?{integer}
real		[+-]?{plain_real}|{short_exp_real}|{exp_real}

number          {real}|{integer}

string          \"[^"\n]+\"

bad_string      \"([^"\n]|\n)+\"

ws		[ \t]+
other		.


/* Rules */ 
%%

include         { if ( scanner_debug ) {
                      printf("return IncludeSym\n");
                  }
                  return IncludeSym;
                }

mesh            { if ( scanner_debug ) {
                      printf("return MeshSym\n");
                  }
                  return MeshSym;
                }

row             { if ( scanner_debug ) {
                      printf("return RowSym\n");
                  }
                  return RowSym;
                }

chunk           { if ( scanner_debug ) {
                      printf("return ChunkSym\n");
                  }
                  return ChunkSym;
                }

bounds          { if ( scanner_debug ) {
                      printf("return BoundsSym\n");
                  }
                  return BoundsSym;
                }

place           { if ( scanner_debug ) {
                      printf("return PlaceSym\n");
                  }
                  return PlaceSym;
                }

{ident}		{ if ( scanner_debug ) {
                      printf("return Identifier = %s\n", yytext);
                  }
                  return Identifier;
                }

{number}	{ if ( scanner_debug ) {
                      printf("return Number\n");
                  }
                  return Number;
                }

{string}        { if ( scanner_debug ) {
                      printf("return StringLiteral = %s\n", yytext);
                  }
                  return StringLiteral;
                }

{bad_string}    { if ( scanner_debug ) {
                      printf("return BadStringLiteral = %s\n", yytext);
                  }
                  return BadStringLiteral; 
                }

"\n"		{ line_num++; 
                  if ( scanner_debug ) {
                      printf("Line number = %d\n", line_num);
                  }
               }

"#"		{ if ( scanner_debug ) {
                      printf("return HashSym\n");
                  }
                  return HashSym; 
                }

"="		{ if ( scanner_debug ) {
                      printf("return EqualSym\n");
                  }
                  return EqualSym; 
                }

","		{ if ( scanner_debug ) {
                      printf("return CommaSym\n");
                  }
                  return CommaSym; 
                }

"{"		{ if ( scanner_debug ) {
                      printf("return LBraceSym\n");
                  }
                  return LBraceSym; 
                }

"}"		{ if ( scanner_debug ) {
                      printf("return RBraceSym\n");
                  }
                  return RBraceSym;
                }

"("		{ if ( scanner_debug ) {
                      printf("return LParenSym\n");
                  }
                  return LParenSym; 
                }

")"		{ if ( scanner_debug ) {
                      printf("return RParenSym\n");
                  }
                  return RParenSym;
                }

"//"    	{ /* burn through "#" comment */ 
		  c = input();
		  while ( (c != '\n') ) {
		      c = input();
		      /* scanner_print("%c", c); */
		  }
		  unput(c);
		  /* line_num++; */
		}

{ws}		{ ; }

{other}		{ if ( scanner_debug ) {
                      printf("Scanned some unexpected text = `%s'\n", yytext);
                  }
		  return ErrorMisc; 
		}

<<EOF>>         { if ( pop_input_stream() == 0 ) {
                      /* End of last input stream */
                      yyterminate();
                  }
                }