/* Bison grammar file for disassembler symbol table file */

%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "disasm.h"

struct symbol *first_sym = NULL, *last_sym;
struct range *first_rng = NULL, *last_rng;
int base_addr;

%}

%union
{
	int num;
	char *string;
	struct symbol *symbol;
	struct range *range;
}

%token	SYMBOL
%token	CODE
%token	DATA
%token	STRING

%token	BASE
%token	START

%token	RANGE

%token	<string>	IDENT
%token	<num>		NUM
%token	<symbol>	SYMBOL
%token	<string>	STRING

%type	<num>		option
%type	<num>		optlist
%type	<symbol>	symblock
%type	<range>		rngblock

%%

input:		  /* blank */
		| block ';' input
		;

block:		  symblock	{
		 			if (first_sym)
						last_sym = last_sym->next = $1;
					else
						last_sym = first_sym = $1;
				}
		| rngblock	{
					if (first_rng)
						last_rng = last_rng->next = $1;
					else
						last_rng = first_rng = $1;
				}
		| BASE NUM		{ base_addr = $2; }
		| START SYMBOL		{ start = $2->addr; }
		| START NUM		{ start = $2; }
		;

symblock:	  SYMBOL IDENT '@' NUM optlist
			{
				$$ = malloc (sizeof (struct symbol));
				$$->next = NULL;
				$$->name = strdup ($2);
				$$->addr = $4;
				$$->type = $5;
			}
		;

rngblock:	  RANGE NUM NUM optlist
			{
				$$ = malloc (sizeof (struct range));
				$$->next = NULL;
				$$->addr = $2;
				$$->end = $3;
				$$->type = $4;
			}
		;

optlist:	  /* empty */		{ $$ = 0; }
		| option optlist	{ $$ = $1 | $2; }
		;

option:		  CODE			{ $$ = SYM_CODE; }
		| DATA			{ $$ = SYM_DATA; }
		| STRING		{ $$ = SYM_STRING; }
		;

%%

int yyerror (char *s)
{
	extern int lineno;
	
	fprintf (stderr, "%s at line %d\n", s, lineno);
	return 0;
}
