/* lex (flex) file for AEC, the AE Compiler.
   Lexical analyzer that recognizes the keywords in a schema file.

   Copyright (C) 1989, 1990 by James R. Larus (larus@cs.wisc.edu)

   NB Must preprocess with cpp -P before giving to lex so that keyword names,
   which are #defines, are expanded.


   AE and AEC are 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 1, or (at your option) any
   later version.

   AE and AEC are 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 GNU CC; see the file COPYING.  If not, write to James R.
   Larus, Computer Sciences Department, University of Wisconsin--Madison,
   1210 West Dayton Street, Madison, WI 53706, USA or to the Free
   Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */

/* $Header: /var/home/larus/AE/AEC/RCS/scanner.l,v 2.0 90/02/09 17:23:48 larus Exp Locker: larus $ */


#include "schema.h"
#include "y.tab.h"

%{
extern int yylval;

/* Keep track of which line we are reading and where it began. */

int line_no = 1;

char *line_start = NULL;

char *remove_periods ();

#define TOKEN(x) {line_start = yytext; return (x);}

%}

%%

FUNCTION_START		{TOKEN (Y_FUNCTION_START);};
FUNCTION_END		{TOKEN (Y_FUNCTION_END);};

BLOCK_START		{TOKEN (Y_BLOCK_START);};
BLOCK_START_TARGET	{TOKEN (Y_BLOCK_START_TARGET);};

BLOCK_END		{TOKEN (Y_BLOCK_END);};
BLOCK_END_NEXT_TARGET	{TOKEN (Y_BLOCK_END_NEXT_TARGET);};
BLOCK_END_JUMP		{TOKEN (Y_BLOCK_END_JUMP);};
BLOCK_END_JUMP_NEXT_TARGET	{TOKEN (Y_BLOCK_END_JUMP_NEXT_TARGET);};
BLOCK_END_CJUMP		{TOKEN (Y_BLOCK_END_CJUMP);};

LOOP_ENTRY		{TOKEN (Y_LOOP_ENTRY);};
LOOP_BACK		{TOKEN (Y_LOOP_BACK);};
LOOP_EXIT		{TOKEN (Y_LOOP_EXIT);};

UNEVENTFUL_INST		{TOKEN (Y_UNEVENTFUL_INST);};

STORE_INST		{TOKEN (Y_STORE_INST);};
STORE_D_INST		{TOKEN (Y_STORE_D_INST);};
STORE_UNKNOWN_INST	{TOKEN (Y_STORE_UNKNOWN_INST);};

LOAD_INST		{TOKEN (Y_LOAD_INST);};
LOAD_D_INST		{TOKEN (Y_LOAD_D_INST);};
LOAD_UNKNOWN_INST	{TOKEN (Y_LOAD_UNKNOWN_INST);};

COMPUTE_DEFN_0		{TOKEN (Y_COMPUTE_DEFN_0);};
COMPUTE_DEFN_1		{TOKEN (Y_COMPUTE_DEFN_1);};
COMPUTE_DEFN_2		{TOKEN (Y_COMPUTE_DEFN_2);};
UNKNOWN_DEFN		{TOKEN (Y_UNKNOWN_DEFN);};

CALL_INST		{TOKEN (Y_CALL_INST);};
CALL_INDIRECT_INST	{TOKEN (Y_CALL_INDIRECT_INST);};


[ \t]			;

[\n]			{return (Y_NL);}

(-[0-9]+)|([0-9]+)	{yylval = atoi (yytext);
			 if (line_start == NULL) line_start = yytext;
			 return (Y_INT);};

R[0-9]+			{yylval = atoi (yytext + 1);
			 return (Y_REG);};

[a-zA-Z_.][a-zA-Z0-9_.]*	{yylval = (int) remove_periods (yytext);
			 if (line_start == NULL) line_start = yytext;
			 return (Y_ID);};

"#"[a-zA-Z0-9_.-]*	{yylval = strcpy (malloc (strlen (yytext) + 1),
					  yytext);
			 return (Y_LIT);};

"-"|[+*/%&|~]|"<<"|">>"	{yylval = strcpy (malloc (strlen (yytext) + 1),
					  yytext);
			 return (Y_OP);};

"("			{return (Y_LPAREN);};
")"			{return (Y_RPAREN);};

%%

void
initialize_scanner (in_file)
     FILE *in_file;
{
  yyin = in_file;
#ifdef FLEX_SCANNER
  yy_init = 1;
#endif
  line_no = 1;
  line_start = NULL;
}


#ifndef FLEX_SCANNER
/* We don't use -ll */
int yywrap () {return 1;}
#endif


/* When the parser has successfully parsed a line, step these
   counters.  They are driven by the parser since they are used to report
   parser error messages. */

void
scanner_nl ()
{
  line_no ++;
  line_start = yytext + 1;
}


/* On a parse error, write out the current line and print a caret (^)
   below the point at which the error occured.  Also, reset input stream
   to begining of next line. */

void
print_erroneous_line (err_file)
     FILE *err_file;
{
  int prefix_length = yytext - line_start;
  int i, c;

  fprintf (err_file, "    ");
  fwrite (line_start, sizeof (char), prefix_length, err_file);
  fprintf (err_file, "%s", yytext);

  /* Flush the rest of the line. */
  if (*yytext != '\n')
    {
      while ((c = input ()) != '\n' && c != EOF) fputc (c, err_file);
      fputc ('\n', err_file);
    }

  fprintf (err_file, "    ");
  for (i = 0; i < prefix_length; i ++) fputc (' ', err_file);
  fprintf (err_file, "^\n");
}


/* Some implementation build internal names with periods.  These names are
   invalid identifiers in C (since dot is a structure selector).  Translate
   a period to _DoT_. */

static char *
remove_periods (str)
     char *str;
{
  int num_dots = 0;
  register char *s, *new_str, *n, *x;

  for (s = str; *s != '\0'; s ++) if (*s == '.') num_dots += 1;
  new_str = (char *) malloc (strlen (str) + 1 + 5 * num_dots);
  for (s = str, n = new_str; *s != '\0'; s ++)
    if (*s == '.')
      for (x = "_DoT_"; *x != '\0'; ) *n ++ = *x ++;
    else
      *n ++ = *s;

  *n = '\0';
  return (new_str);
}
