%{
/* Copyright (C) 1991 Free Software Foundation, Inc.

This file is part of GLD, the Gnu Linker.

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

GLD 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 GLD; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

/*
 *  $Id$ 

 *
*/



/*SUPPRESS 529*/
/*SUPPRESS 26*/
/*SUPPRESS 29*/
#define LEXDEBUG 0
#include "sysdep.h"
#include "bfd.h"

#include <ctype.h>
#include "ldlex.h"

#include "ld.h"
#include "ldexp.h"
#include "ldgram.tab.h"
#include "ldmisc.h"

#undef input
#undef unput
#define input lex_input
#define unput lex_unput
int debug;


static boolean ldgram_in_defsym;
static boolean ldgram_had_equals;
extern boolean ldgram_in_script;
static char *command_line;

extern int fgetc();
extern int yyparse();

typedef struct {
	char *name;	
int value;
} keyword_type;
#define RTOKEN(x)  {  yylval.token = x; return x; }
keyword_type keywords[] = 
{
"/", '/',
"MEMORY",MEMORY,
"ORIGIN",ORIGIN,
"BLOCK",BLOCK,
"LENGTH",LENGTH,
"ALIGN",ALIGN_K,
"ADDR",ADDR,
"ENTRY",ENTRY,
"NEXT",NEXT,
"sizeof_headers",SIZEOF_HEADERS,
"SIZEOF_HEADERS",SIZEOF_HEADERS,
"MAP",MAP,
"SIZEOF",SIZEOF,
"TARGET",TARGET_K,
"SEARCH_DIR",SEARCH_DIR,
"OUTPUT",OUTPUT,
"INPUT",INPUT,
"DEFINED",DEFINED,
"CREATE_OBJECT_SYMBOLS",CREATE_OBJECT_SYMBOLS,
"FORCE_COMMON_ALLOCATION",FORCE_COMMON_ALLOCATION,
"SECTIONS",SECTIONS,
"FILL",FILL,
"STARTUP",STARTUP,
"OUTPUT_FORMAT",OUTPUT_FORMAT,
"OUTPUT_ARCH", OUTPUT_ARCH,
"HLL",HLL,
"SYSLIB",SYSLIB,
"FLOAT",FLOAT,
"LONG", LONG,
"SHORT", SHORT,
"BYTE", BYTE,
"NOFLOAT",NOFLOAT,
"o",ORIGIN,
"org",ORIGIN,
"l", LENGTH,
"len", LENGTH,
0,0};
unsigned int lineno;
extern boolean hex_mode;
FILE *ldlex_input_stack;
static unsigned int have_pushback;

#define NPUSHBACK 10
int pushback[NPUSHBACK];
int thischar;
extern char *ldfile_input_filename;
int donehash = 0;
int
lex_input()
{
  if (have_pushback > 0) 
      {
	have_pushback --;
	return thischar = pushback[have_pushback];
      }
  if (ldlex_input_stack) {
    thischar = fgetc(ldlex_input_stack);

    if (thischar == EOF)  {
      fclose(ldlex_input_stack);
      ldlex_input_stack = (FILE *)NULL;
      ldfile_input_filename = (char *)NULL;
      /* First char after script eof is a @ so that we can tell the grammer
	 that we've left */
      thischar = '@';

    }
  }
  else if (command_line && *command_line)  {
    thischar = *(command_line++);
  }
  else {
 thischar = 0;
  }
  if(thischar == '\t') thischar = ' ';
  if (thischar == '\n') { thischar = ' '; lineno++; }
  return thischar ;
}

void
lex_unput(c)
int c;
{
  if (have_pushback > NPUSHBACK) {
    info("%F%P Too many pushbacks\n");
  }

  pushback[have_pushback] = c;
  have_pushback ++;
}


	int
yywrap()
	 { return 1; }
/*VARARGS*/

void
allprint(x) 
int x;
{
fprintf(yyout,"%d",x);
}

void
sprint(x) 
char *x;
{
fprintf(yyout,"%s",x);
}

int  thischar;

void parse_line(arg)
char *arg;
{
  command_line = arg;
  have_pushback = 0;
  yyparse();
}



void
parse_args(ac, av)
int ac;
char **av;
{
  char *p;
  int i;
  size_t size = 0;
  char *dst;
  debug = 1;
  for (i= 1; i < ac; i++) {
    size += strlen(av[i]) + 2; 
  }
  dst = p = (char *)ldmalloc(size + 2);
/* Put a space arount each option */


  for (i =1; i < ac; i++) {

    unsigned int s = strlen(av[i]);
  *dst++ = ' ';
    memcpy(dst, av[i], s);
    dst[s] = ' ';
    dst += s + 1;
  }
  *dst	= 0;
  parse_line(p);

  free(p);


}

static long 
DEFUN(number,(default_if_zero,base),
      int default_if_zero AND
      int base)
{
  unsigned  long l = 0;
  int ch = yytext[0];
  if (ch == 0) {
    base = default_if_zero;
  }
  while (1) {
    switch (ch) {
    case 'x':
      base = 16;
      break;
    case 'k':
    case 'K':
      l =l * 1024;
      break;
    case 'm':
    case 'M':
      l =l * 1024 * 1024;
      break;
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9':
      l = l * base + ch - '0';
      break;
    case 'a': case 'b': case 'c' : case 'd' : case 'e': case 'f':
      l =l *base + ch - 'a' + 10;
      break;
    case 'A': case 'B': case 'C' : case 'D' : case 'E': case 'F':
      l =l *base + ch - 'A' + 10;
      break;
    default:
      unput(ch);
      yylval.integer = l;
      return INT;
    }
ch = input();
  }
}
%}

%a 4000
%o 5000
FILENAMECHAR	[a-zA-Z0-9\/\.\-\_\+\=]
FILENAME	{FILENAMECHAR}+
WHITE		[ \t]+ 

%%

"@" { return '}'; }
"\ -defsym\ " { ldgram_in_defsym = true; return OPTION_defsym; }
"\ -noinhibit_exec\ " { return OPTION_noinhibit_exec; }
"\ -sort_common\ " { return OPTION_sort_common;}
"\ -format\ " { return OPTION_format; }
"\ -n\ "		{ return OPTION_n; }
"\ -r\ "		{ return OPTION_r; }
"\ -i\ "		{ return OPTION_r; }
"\ -Ur\ "		{ return OPTION_Ur; }
"\ -o\ "		{ return OPTION_o; }
"\ -g\ "		{ return OPTION_g; }
"\ -e\ "		{ return OPTION_e; }
"\ -b\ "		{ return OPTION_b; }
"\ -dc\ "		{ return OPTION_dc; }
"\ -dp\ "		{ return OPTION_dp; }
"\ -d\ "		{ return OPTION_d; }
"\ -v\ "		{ return OPTION_v; }
"\ -M\ "		{ return OPTION_M; }
"\ -t\ "		{ return OPTION_t; }
"\ -X\ "		{ return OPTION_X; }
"\ -x\ "		{ return OPTION_x; }
"\ -c\ "		{ return OPTION_c; }
"\ -R\ "		{ return OPTION_R; }
"\ -u\ "		{ return OPTION_u; }
"\ -s\ "            { return OPTION_s; }
"\ -S\ "            { return OPTION_S; }
"\ -B{FILENAME}\ "    { /* Ignored */ }
"\ -l"{FILENAME} {
	 	yylval.name = buystring(yytext+3);
		return OPTION_l; 
	}

"\ -L"{FILENAME} 	{ 
		yylval.name = buystring(yytext+3);
	 	return OPTION_L; 
	 }
"\ -Ttext\ "  {
		 yylval.name = ".text";
		 return OPTION_Texp;
	       }
"\ -Tdata\ "  {
		 yylval.name = ".data";
		 return OPTION_Texp;
	       }
"\ -Tbss\ "  {
		 yylval.name = ".bss";
		 return OPTION_Texp;
	       }

"\ -T"{FILENAME}  {
		 yylval.name = buystring(yytext+3);
		 return OPTION_Tfile;
	       }
"\ -T\ "          {
		 return OPTION_T;
	       }

"\ -F"{FILENAME}  {
		 return OPTION_F;
	       }
"\ -F\ "          {
		 return OPTION_F;
	       }

"\ -A"{FILENAME} {
                 yylval.name = buystring(yytext+3);
		 return OPTION_Aarch;
	       }

" "		{
		 if (ldgram_had_equals == true) {
			  ldgram_in_defsym = false;
			  ldgram_had_equals = false;
		  }
	}
"<<="		{ RTOKEN(LSHIFTEQ);}
">>="		{ RTOKEN(RSHIFTEQ);}
"||"		{ RTOKEN(OROR);}
"=="		{ RTOKEN(EQ);}
"!="		{ RTOKEN(NE);}
">="		{ RTOKEN(GE);}
"<="		{ RTOKEN(LE);}
"<<"		{ RTOKEN(LSHIFT);}
">>"		{ RTOKEN(RSHIFT);}
"+="		{ RTOKEN(PLUSEQ);}
"-="		{ RTOKEN(MINUSEQ);}
"*="		{ RTOKEN(MULTEQ);}
"/="		{ RTOKEN(DIVEQ);}
"&="		{ RTOKEN(ANDEQ);}
"|="		{ RTOKEN(OREQ);}
"&&"		{ RTOKEN(ANDAND);}
">"		{ RTOKEN('>');}
","		{ RTOKEN(',');}
"&"		{ RTOKEN('&');}
"|"		{ RTOKEN('|');}
"~"		{ RTOKEN('~');}
"!"		{ RTOKEN('!');}
"?"		{ RTOKEN('?');}
"*"		{ RTOKEN('*');}
"%"		{ RTOKEN('%');}
"<"		{ RTOKEN('<');}
">"		{ RTOKEN('>');}
"}"		{ RTOKEN('}') ; }
"{"		{ RTOKEN('{'); }
")"		{ RTOKEN(')');}
"("		{ RTOKEN('(');}
"]"		{ RTOKEN(']');}
"["		{ RTOKEN('[');}
":"		{ RTOKEN(':'); }
";"		{ RTOKEN('\;');}
"-"		{ RTOKEN('-');}



"/*"		{ 
  while (1) {
    int ch;
    ch = input();
    while (ch != '*') {
      ch = input();
    }



    if (input() == '/') {
      break;
    }
    unput(yytext[yyleng-1]);
  }
}

"\""[^\"]*"\"" {

  yylval.name = buystring(yytext+1);
  yylval.name[yyleng-2] = 0; /* Fry final quote */
  return NAME;
}

{FILENAMECHAR} {

  boolean loop = false;
  int ch;
  keyword_type *k;

  /* If we're in hex mode (only after a -T) then all we can see are numbers
     hex digit we see will be a number. */

  if (hex_mode) {	
    return number(16, 16);
  }

  /* If we're in a defsym then all things starting with a digit are in
     hex */

  if (isdigit(yytext[0]) && ldgram_in_defsym) {
    return number(16,16);
  }


  /* Otherwise if we're in a script we will parse the numbers
     normally */

  if (ldgram_in_script == true && isdigit(yytext[0])) {
    return number(8,10);
  }

  /* Anywhere not in a script or defsym, an opertor is part of a
     filename, except / and, which is an operator when on its own */
  if (ldgram_in_script == true|| ldgram_in_defsym == true) {

    switch (yytext[0]) {
      case '*': RTOKEN('*');

      case '=': {
	ldgram_had_equals = true;
	RTOKEN('=');
      }
	break;
     case '/': {
       if (ldgram_in_defsym) RTOKEN('/');
     }
	break;
      case '+': RTOKEN('+');
      case '-': RTOKEN('-');
      case '!': RTOKEN('!');
      case '~': RTOKEN('~');
      }
    }


/* Otherwise this must be a file or a symbol name, and it will continue to be a
   filename until we get to something strange. In scripts operator looking
   things  are taken to be operators, except /, which will be left
 */
  ch = input();
  while (true)
      {
	if (ldgram_in_defsym == true) {
	  switch (ch) {
	  case '*': 
	  case '=': 
	  case '+': 
	  case '/': 
	  case '-': 
	  case '!': 
	  case '~': 
	    goto quit;
	  }
	  
	}
	if(ldgram_in_script == true) {
	  switch (ch) {
	  case '*': 
	  case '=': 
	  case '+': 
	  case '-': 
	  case '!': 
	  case '~': 
	    goto quit;
	  }
        }

	if (isalpha(ch) || isdigit(ch) || ch == '.'  || ch == '_'  ||
	    ch == '/' || ch == '.' || ch == '+' || ch == '-' || ch =='=') {
	  yytext[yyleng++] = ch;
	}
	else 
	  break;
	ch = input();
      }
 quit:;
  yytext[yyleng] = 0;
  unput(ch);

  for(k = keywords; k ->name != (char *)NULL; k++) {
    if (strcmp(k->name, yytext)==0) {
      yylval.token = k->value;
      return k->value;
    }
  }
  yylval.name = buystring(yytext);
  return NAME;
}





%%