upecc.l
%x include byte_order multi

%{
/* UPE compiler - lexer
 * (c)2000 Stepan Roh
 * see license.txt for copying
 */
 
#include <stdlib.h>
#include <string.h>
#include <values.h>
#include <errno.h>
#include "upe.h"
#include "upecc.h"
#include "upecc_tree.h"
#include "upecc.tab.h"
void inc_parser_line (void);
int yyerror(char *);
void err_no_mem (void);
int add_include (char *name, FILE *f);
int del_include (void);
extern char err_tmp[1024];

%}

DEC_DIGIT	[0-9]
HEX_DIGIT	[0-9a-fA-F]
BIN_DIGIT	[0-1]
OCT_DIGIT	[0-7]
ID		[[:alpha:]_][[:alnum:]_]*
HEX_INT		0x{HEX_DIGIT}+
BIN_INT		0b{BIN_DIGIT}+
OCT_INT 	0{OCT_DIGIT}+
DEC_INT		{DEC_DIGIT}+
INT		{HEX_INT}|{BIN_INT}|{OCT_INT}|{DEC_INT}
SEP		[\t \n\r]+
LSEP		[\t ]+

%%
{INT}		{
		  if (!(yylval.num = upe_initnum (upecc_num_len, 0, UPE_NO_SIGN))) err_no_mem ();
		  upe_zeronum (yylval.num);
		  upe_strtonum (yylval.num, yytext);
                  return T_NUM;
		}
               
"//"[^\n]*\n		{ inc_parser_line (); }

"/*"			{ BEGIN(multi); }

<multi>"*/"		{ BEGIN(INITIAL); }

<multi>\n		{ inc_parser_line (); }

<multi>.		{}

"#"[^\n]*\n		{ inc_parser_line (); }

"as"{SEP}		{ inc_parser_line ();
			  return T_AS; }

"ip"{SEP}		{ inc_parser_line ();
			  return T_IP; }

"array"{SEP}		{ inc_parser_line ();
			  return T_ARRAY; }

"var"{SEP}		{ inc_parser_line ();
			  return T_VAR; }

"break"{SEP}		{ inc_parser_line ();
			  return T_BREAK; }

"break"/;		{ inc_parser_line ();
			  return T_BREAK; }

"continue"{SEP}		{ inc_parser_line ();
			  return T_CONTINUE; }

"continue"/;		{ inc_parser_line ();
			  return T_CONTINUE; }

"register"{SEP}		{ inc_parser_line ();
			  return T_REGISTER; }

"include"		{ BEGIN(include); }

<include>{SEP}		{ inc_parser_line (); }

<include>"\""[^"]*"\""	{ FILE *f; char *fname;
			  if (!(fname = strdup (yytext + 1))) err_no_mem ();
			  fname[strlen (fname) - 1] = 0;
			  inc_parser_line ();
			  if (!(f = fopen (fname, "r"))) {
			    sprintf (err_tmp, "error opening input file %s : %s\n", fname, strerror (errno));
			    yyerror (err_tmp);
			    return -1;
			  }
			  if (add_include (fname, f)) return -1;
			  free (fname);
			  BEGIN(INITIAL); }

<include>.		{ yyerror ("parse error");
			  return -1; }
			  
"byte_size"{SEP}	{ inc_parser_line ();
			  return T_BYTE_SIZE; }

"byte_order"		{ BEGIN(byte_order);
			  return T_BYTE_ORDER; }

<byte_order>"\n"	{ inc_parser_line ();
			  BEGIN(INITIAL); }

<byte_order>{LSEP}	

<byte_order>[1-9]+	{ if (!(yylval.id = strdup (yytext))) err_no_mem ();
		  	  return T_BYTE_ORDER_ID; }

<byte_order>","		{ return T_COMMA; }

<byte_order>.		{ yyerror ("parse error");
			  return -1; }

"numbers_len"{SEP}	{ inc_parser_line ();
			  return T_NUM_LEN; }

"instructions"{SEP}	{ inc_parser_line ();
			  return T_INSTRUCTIONS; }

"function"{SEP}		{ inc_parser_line ();
			  return T_FUNCTION; }

"constant"{SEP}		{ inc_parser_line ();
			  return T_CONSTANT; }

"return"{SEP}		{ inc_parser_line ();
			  return T_RETURN; }

"external"{SEP}		{ inc_parser_line ();
			  return T_EXTERNAL; }

"while"{SEP}		{ inc_parser_line ();
			  return T_WHILE; }

"do"{SEP}		{ inc_parser_line ();
			  return T_DO; }

"if"{SEP}		{ inc_parser_line ();
			  return T_IF; }

"else"{SEP}		{ inc_parser_line ();
			  return T_ELSE; }

"for"{SEP}		{ inc_parser_line ();
			  return T_FOR; }

{ID}		{
		  if (!(yylval.id = strdup (yytext))) err_no_mem ();
		  return T_ID;
		}

"\""[^"]*"\""	{ char *tmp;
		  if (!(tmp = strdup (yytext + 1))) err_no_mem ();
		  tmp[strlen (tmp) - 1] = 0;
		  inc_parser_line ();
		  yylval.id = tmp;
		  return T_STR;
		}

"++"		{ return T_INC; }

"--"		{ return T_DEC; }

"+="		{ return T_ASSIGN_PLUS; }
		
"+"		{ return T_PLUS; }

"-="		{ return T_ASSIGN_MINUS; }

"-"		{ return T_MINUS; }

"("		{ return T_OPEN_PARENT; }

")"		{ return T_CLOSE_PARENT; }

":"		{ return T_COLON; }

"?"		{ return T_QUOTE; }

"{"		{ return T_OPEN_BRACKET; }

"}"		{ return T_CLOSE_BRACKET; }

";"		{ return T_SEMICOLON; }

","		{ return T_COMMA; }

"<<="		{ return T_ASSIGN_SHIFT_LEFT; }

"<<"		{ return T_SHIFT_LEFT; }

">>="		{ return T_ASSIGN_SHIFT_RIGHT; }

">>"		{ return T_SHIFT_RIGHT; }

"=="		{ return T_EQUALS; }

"!="		{ return T_NON_EQUALS; }

"<"		{ return T_LESS_THAN; }

"<="		{ return T_LESS_OR_EQUAL; }

">"		{ return T_GREATER_THAN; }

">="		{ return T_GREATER_OR_EQUAL; }

"="		{ return T_ASSIGN; }

"!"		{ return T_NEG; }

"&&"		{ return T_AND; }

"||"		{ return T_OR; }

"&="		{ return T_ASSIGN_BITAND; }

"&"		{ return T_BITAND; }

"|="		{ return T_ASSIGN_BITOR; }

"|"		{ return T_BITOR; }

"^="		{ return T_ASSIGN_BITXOR; }

"^"		{ return T_BITXOR; }

"~"		{ return T_BITNEG; }

{SEP}		{ inc_parser_line (); }

.		{ return (int) yytext[0]; }

<<EOF>>		{ if (del_include ()) yyterminate (); }

%%

/* counts number of nelines, and increase parser_line appropriately */
void inc_parser_line (void) {
  char *x = yytext;
  while ((x = strchr (x, '\n'))) {
    parser_line++;
    x++;
  }
}

/* include file names struct
 * - once included, everytime stored
 *   because name is used widely across parser and generator
 */
typedef struct include_file_name {
  char *name;				/* file name */
  struct include_file_name *next;	/* next in chain */
} include_file_name;

/* include info for includes[] stack */
typedef struct include_info {
  char *name;				/* file name */
  int line;				/* actual line */
  YY_BUFFER_STATE yy_buf;		/* lexer buffer state */
} include_info;

/* include file names list */
include_file_name *include_names;

/* includes stack */
include_info includes[MAX_INCLUDE_DEPTH];

/* pointer to includes[] stack */
int includes_ptr = -1;

/* add new include - must be opened
 * switches into new file
 * returns 0 on success, -1 on error
 */
int add_include (char *name, FILE *f) {
  char *dname; include_file_name *ifname;
  
  if (!(dname = strdup (name))) err_no_mem ();
  if (!(ifname = malloc (sizeof (include_file_name)))) err_no_mem ();
  ifname->next = include_names;
  include_names = ifname;
  ifname->name = dname;
  
  if (includes_ptr >= MAX_INCLUDE_DEPTH - 1) {
    yyerror ("includes nested too deeply");
    return -1;
  }
  
  includes[includes_ptr].line = parser_line;
  
  includes_ptr++;
  
  includes[includes_ptr].name = parser_file = dname;
  includes[includes_ptr].line = parser_line = 1;
  yyin = f;
  includes[includes_ptr].yy_buf = yy_create_buffer (yyin, YY_BUF_SIZE);
  yy_switch_to_buffer (includes[includes_ptr].yy_buf);
  
  return 0;
}

/* del last include
 * switches into previous file
 * returns 0 on success, 1 on empty includes stack
 */
int del_include (void) {

  if (--includes_ptr >= 0) {
  
    parser_file = includes[includes_ptr].name;
    parser_line = includes[includes_ptr].line;
    yy_delete_buffer (YY_CURRENT_BUFFER);
    yy_switch_to_buffer (includes[includes_ptr].yy_buf);
    
    return 0;
  }
  
  return 1;
}

