[56e3db]: / c2iec.y  Maximize  Restore  History

Download this file

1077 lines (947 with data), 23.5 kB

%token IDENTIFIER CONSTANT STRING_LITERAL SIZEOF
%token PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP
%token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN
%token SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN
%token XOR_ASSIGN OR_ASSIGN TYPE_NAME

%token TYPEDEF EXTERN STATIC AUTO REGISTER INLINE RESTRICT
%token CHAR SHORT INT LONG SIGNED UNSIGNED FLOAT DOUBLE CONST VOLATILE VOID
%token BOOL COMPLEX IMAGINARY
%token STRUCT UNION ENUM ELLIPSIS

%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN

%union { char str[4096]; }

%start translation_unit

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

// enable debug prints for this file
#ifdef DEBUG
  #define DEBUG_PRINT(args...) printf(args)
#else
  #define DEBUG_PRINT(args...) 
#endif
  
// get tail of a string
#define TAIL(str) (&str[strlen(str)])


// fifo to store expression strings
#define STMT_SIZE 1024
#define FIFO_SIZE 200

typedef enum
{
	decl_all,
	decl_param,
	decl_func,
	fifo_entry_num /* reflects the number of enum entries */
} fifo_entry_t;

typedef struct
{
	char fifo[FIFO_SIZE][STMT_SIZE];
	unsigned int read;
	unsigned int write;
} fifo_t;

static fifo_t s_fifos[fifo_entry_num];
void yyerror(char const *s);

// push an entry (typically a declaration into the fifo
void fifo_push(fifo_entry_t type, const char *psz);

// pop one entry from the specific category
char *fifo_pop(fifo_entry_t type);
char *lifo_pop(fifo_entry_t type);

// tag all from category "all" to new type
// this way we can collect new stuff in all and push
// it to the correct section when we know more about
// our context
void fifo_tag(fifo_entry_t type);

// check if fifo is empty
int fifo_empty(fifo_entry_t type);

// check fill status of queue
int fifo_size(fifo_entry_t type);

// map c datatype to iec (standard and userdefined)
char *maptype(char *ctype);

// get identifier from payload data
// when used e.g. with the declarator of a struct,
// the name is reproducable
char *genIdentifier(char *szData);

// convert input string to upper case
char *strUpper(char *szStr);

// check if string a starts with string b
int strStartsWith(const char *a, const char *b);

// terminate string after identifier boundary
char *strIdentifier(char *szStr);

// add symbol name to symbol table
#define SYM_SIZE 128
#define SYM_COUNT 1024
int s_iSymTabCount = 0;
char s_szSymTab[SYM_COUNT][SYM_SIZE];
void addSym(char *szSym);
int isSym(char *szSym);

// define function name of current context
static char s_szFuncName[SYM_SIZE];
void setFunctionName(char *szName);
char *getFunctionName(void);

// lex/yacc functions
extern int yylex (void);
%}

%%

primary_expression
	: IDENTIFIER
	| CONSTANT
	| STRING_LITERAL
	| '(' expression ')'
	{ sprintf($<str>$, "( %s )",$<str>2); }
	;

postfix_expression
	: primary_expression
	{ sprintf($<str>$, "%s",$<str>1); }
	| postfix_expression '[' expression ']'
	{ sprintf($<str>$, "%s[%s]",$<str>1, $<str>3); }
	| postfix_expression '(' ')'
	{ sprintf($<str>$, "%s()",$<str>1); }
	| postfix_expression '(' argument_expression_list ')'
	{ sprintf($<str>$, "%s(%s)",$<str>1, $<str>3); }
	| postfix_expression '.' IDENTIFIER
	{ sprintf($<str>$, "%s.%s",$<str>1,$<str>3); }
	| postfix_expression PTR_OP IDENTIFIER
	{ sprintf($<str>$, "%s %s %s",$<str>1, $<str>2, $<str>3);}
	| postfix_expression INC_OP
	{ sprintf($<str>$, "%s:=%s+1",$<str>1, $<str>1); }
	| postfix_expression DEC_OP
	{ sprintf($<str>$, "%s:=%s-1",$<str>1, $<str>1); }
	| '(' type_name ')' '{' initializer_list '}'
	| '(' type_name ')' '{' initializer_list ',' '}'
	;

argument_expression_list
	: assignment_expression
	| argument_expression_list ',' assignment_expression
	{ sprintf($<str>$, "%s, %s",$<str>1, $<str>3); }
	;

unary_expression
	: postfix_expression
	| INC_OP unary_expression
	{ sprintf($<str>$, "(%s:=%s+1)",$<str>2, $<str>2); }
	| DEC_OP unary_expression
	{ sprintf($<str>$, "(%s:=%s-1)",$<str>2, $<str>2); }
	| unary_operator cast_expression
	{
	    if (!strcmp($<str>1, "*"))
	    {
		sprintf($<str>$, "%s^",$<str>2);
	    }
	    else
	    {
		sprintf($<str>$, "%s%s",$<str>1, $<str>2);
	    }
	}
	| SIZEOF unary_expression
	{ sprintf($<str>$, "%s %s",$<str>1, $<str>2); }
	| SIZEOF '(' type_name ')'
	{ sprintf($<str>$, "%s (%s)",$<str>1, $<str>3); }
	;

unary_operator
	: '&'
	| '*'
	| '+'
	| '-'
	| '~'
	| '!'
	;

cast_expression
	: unary_expression
	| '(' type_name ')' cast_expression
	{ sprintf($<str>$, "ANY_TO_%s(%s)",$<str>2, $<str>4); }
	;

multiplicative_expression
	: cast_expression
	| multiplicative_expression '*' cast_expression
	{ sprintf($<str>$, "%s * %s",$<str>1, $<str>3); }
	| multiplicative_expression '/' cast_expression
	{ sprintf($<str>$, "%s / %s",$<str>1, $<str>3); }
	| multiplicative_expression '%' cast_expression
	{ sprintf($<str>$, "%s %s",$<str>1, $<str>3); }
	;

additive_expression
	: multiplicative_expression
	| additive_expression '+' multiplicative_expression
	{ sprintf($<str>$, "%s + %s",$<str>1, $<str>3); }
	| additive_expression '-' multiplicative_expression
	{ sprintf($<str>$, "%s - %s",$<str>1, $<str>3); }
	;

shift_expression
	: additive_expression
	| shift_expression LEFT_OP additive_expression
	{ sprintf($<str>$, "SHL(%s, %s)",$<str>1, $<str>3); }
	| shift_expression RIGHT_OP additive_expression
	{ sprintf($<str>$, "SHR(%s, %s)",$<str>1, $<str>3); }
	;

relational_expression	: shift_expression
	| relational_expression '<' shift_expression
	{ sprintf($<str>$, "%s < %s",$<str>1, $<str>3); }
	| relational_expression '>' shift_expression
	{ sprintf($<str>$, "%s > %s",$<str>1, $<str>3); }
	| relational_expression LE_OP shift_expression
	{ sprintf($<str>$, "%s <= %s",$<str>1, $<str>3); }
	| relational_expression GE_OP shift_expression
	{ sprintf($<str>$, "%s >= %s",$<str>1, $<str>3); }
	;

equality_expression
	: relational_expression
	| equality_expression EQ_OP relational_expression
	{ sprintf($<str>$, "%s = %s",$<str>1, $<str>3); }
	| equality_expression NE_OP relational_expression
	{ sprintf($<str>$, "%s <> %s",$<str>1, $<str>3); }
	;

and_expression
	: equality_expression
	| and_expression '&' equality_expression
	{ sprintf($<str>$, "%s AND %s",$<str>1, $<str>3); }
	;

exclusive_or_expression
	: and_expression
	| exclusive_or_expression '^' and_expression
	{ sprintf($<str>$, "%s XOR %s",$<str>1, $<str>3); }
	;

inclusive_or_expression
	: exclusive_or_expression
	| inclusive_or_expression '|' exclusive_or_expression
	{ sprintf($<str>$, "%s OR %s",$<str>1, $<str>3); }
	;

logical_and_expression
	: inclusive_or_expression
	| logical_and_expression AND_OP inclusive_or_expression
	{ sprintf($<str>$, "%s AND %s",$<str>1, $<str>3); }
	;

logical_or_expression
	: logical_and_expression
	| logical_or_expression OR_OP logical_and_expression
	{ sprintf($<str>$, "%s OR %s",$<str>1, $<str>3); }
	;

conditional_expression
	: logical_or_expression
	| logical_or_expression '?' expression ':' conditional_expression
	;

assignment_expression
	: conditional_expression
	| unary_expression assignment_operator assignment_expression
	{ sprintf($<str>$, "%s %s %s",$<str>1, $<str>2, $<str>3); }
	;

assignment_operator
	: '='
	{ sprintf($<str>$, ":="); }
	| MUL_ASSIGN
	| DIV_ASSIGN
	| MOD_ASSIGN
	| ADD_ASSIGN
	| SUB_ASSIGN
	| LEFT_ASSIGN
	| RIGHT_ASSIGN
	| AND_ASSIGN
	| XOR_ASSIGN
	| OR_ASSIGN
	;

expression
	: assignment_expression
	| expression ',' assignment_expression
	;

constant_expression
	: conditional_expression
	;

declaration
	: declaration_specifiers ';'
	{ sprintf($<str>$, "%s %s;\n",$<str>1, $<str>2); }
	| TYPEDEF declaration_specifiers init_declarator_list ';'
	{
		char *p;
		while( (p=fifo_pop(decl_func)) != NULL)
			/* noop */;
		while( (p=fifo_pop(decl_all)) != NULL)
			/* noop */;
		if (strlen($<str>3) > 0)
		{
			printf("TYPE ");
			printf($<str>3, $<str>2);
			addSym(strIdentifier($<str>3));
			printf("END_TYPE\n\n");
		}
		else
		{
			addSym($<str>4);
		}
		strcpy($<str>$, "");
	}
	| declaration_specifiers init_declarator_list ';'
	{
		char *p;
		int isFuncDecl = 0;
		while( (p=fifo_pop(decl_func)) != NULL)
		{
			printf(p, $<str>1);
			isFuncDecl = 1;
		}
		if (!fifo_empty(decl_param))
		{
		    printf("\nVAR_IN_OUT\n");
		    while( (p=fifo_pop(decl_param)) != NULL)
		    {
			printf(p, $<str>1);
//			isFuncDecl = 0;
		    }
		    printf("\nEND_VAR\n");
		}
		if (!fifo_empty(decl_all))
		{
		    printf("\nVAR\n");
		    while( (p=fifo_pop(decl_all)) != NULL)
		    {
			if (!strStartsWith(p, getFunctionName()))
			{
			    printf(p, $<str>1);
			    isFuncDecl = 0;
			}
		    }
		    printf("\nEND_VAR\n");
		}
		strcpy($<str>$, "");

		if (isFuncDecl)
		    printf("\nEND_FUNCTION\n\n");
	}
	;

declaration_specifiers
	: storage_class_specifier
	| storage_class_specifier declaration_specifiers
	{ sprintf($<str>$, "%s %s",$<str>1, $<str>2); }
	| type_specifier
	{
		sprintf($<str>$, "%s",maptype($<str>1));
	}
	| type_specifier declaration_specifiers
	{
		sprintf($<str>$, "%s %s",$<str>1, $<str>2);
		sprintf($<str>$, "%s",maptype($<str>$));
	}
	| type_qualifier
	| type_qualifier declaration_specifiers
	{ sprintf($<str>$, "%s %s",$<str>1, $<str>2); }
	| function_specifier
	| function_specifier declaration_specifiers
	{ sprintf($<str>$, "%s %s",$<str>1, $<str>2); }
	;

init_declarator_list
	: init_declarator
	| init_declarator_list ',' init_declarator
	{ sprintf($<str>$, "%s, %s",$<str>1, $<str>3); }
	;

init_declarator
	: declarator
	| declarator '=' initializer
	{ sprintf($<str>$, "%s = %s",$<str>1, $<str>3); }
	;

storage_class_specifier
	: TYPEDEF
	| EXTERN
	| STATIC
	{ strcpy($<str>$, ""); }
	| AUTO
	| REGISTER
	;

type_specifier
	: VOID
	| CHAR
	| SHORT
	| INT
	| LONG
	| FLOAT
	| DOUBLE
	| SIGNED
	| UNSIGNED
	| BOOL
	| COMPLEX
	| IMAGINARY
	| struct_or_union_specifier
	| enum_specifier
	| TYPE_NAME
	;

struct_or_union_specifier
	: struct_or_union IDENTIFIER '{' struct_declaration_list '}'
	{
		printf("TYPE %s:\n%s\n %s\nEND_STRUCT\nEND_TYPE\n\n", $<str>2, strUpper($<str>1), $<str>4);
		strcpy($<str>$, $<str>2);
	}
	| struct_or_union '{' struct_declaration_list '}'
	{
		char *szTypeName = genIdentifier($<str>3);
		printf("TYPE %s:\n%s\n %s\nEND_STRUCT\nEND_TYPE\n\n", szTypeName, strUpper($<str>1), $<str>3);
		strcpy($<str>$, szTypeName);
	}
	| struct_or_union IDENTIFIER
	;

unnamed_struct_or_union_specifier
	: struct_or_union '{' struct_declaration_list '}'
	{
		strcpy($<str>$, $<str>3);
	}
	;

struct_or_union
	: STRUCT
	| UNION
	;

struct_declaration_list
	: struct_declaration
	{
		sprintf($<str>$, "%s",maptype($<str>1));
	}
	| struct_declaration_list struct_declaration
	{ sprintf($<str>$, "%s %s",$<str>1, $<str>2); }
	;

struct_declaration
	: specifier_qualifier_list struct_declarator_list ';'
	{
		char *p;
		while( (p=fifo_pop(decl_all)) != NULL)
		{
			strcpy($<str>$, "");
			sprintf(TAIL($<str>$), p, $<str>1);
		}
	}
	| unnamed_struct_or_union_specifier ';'
	;

// as a lexxer hack, I added a special case for typedefs
// to the declaration rule
//specifier_qualifier_list
//	: TYPEDEF type_specifier specifier_qualifier_list
//	{ sprintf($<str>$, "lexxer hack - typedef found\n"); }

specifier_qualifier_list
	: type_specifier specifier_qualifier_list
	{
		sprintf($<str>$, "%s %s", $<str>1, $<str>2);
		sprintf($<str>$, "%s",maptype($<str>$));
	}
	| type_specifier
	{
		strcpy($<str>$, maptype($<str>1));
	}
	| type_qualifier specifier_qualifier_list
	{
		sprintf($<str>$, "%s %s",$<str>1, $<str>2);
		sprintf($<str>$, "%s",maptype($<str>$));
	}
	| type_qualifier
	;

struct_declarator_list
	: struct_declarator
	| struct_declarator_list ',' struct_declarator
	{ sprintf($<str>$, "%s, %s",$<str>1, $<str>3); }
	;

struct_declarator
	: declarator
	| ':' constant_expression
	| declarator ':' constant_expression
	;

enum_specifier
	: ENUM '{' enumerator_list '}'
	| ENUM IDENTIFIER '{' enumerator_list '}'
	| ENUM '{' enumerator_list ',' '}'
	| ENUM IDENTIFIER '{' enumerator_list ',' '}'
	| ENUM IDENTIFIER
	;

enumerator_list
	: enumerator
	| enumerator_list ',' enumerator
	;

enumerator
	: IDENTIFIER
	| IDENTIFIER '=' constant_expression
	;

type_qualifier
	: CONST
	{ strcpy($<str>$, ""); }
	| RESTRICT
	{ strcpy($<str>$, ""); }
	| VOLATILE
	{ strcpy($<str>$, ""); }
	;

function_specifier	: INLINE
	;

declarator
	: pointer direct_declarator
	{ 
	    sprintf($<str>$, "%s: POINTER TO %%s;\n",$<str>2);
	    fifo_push(decl_all, $<str>$);
	}
	| direct_declarator
	{
	    if (strlen($<str>1) > 0)
	    {
		sprintf($<str>$, "%s: %%s;\n",$<str>1);
		fifo_push(decl_all, $<str>$);
	    }
	}
	;

declarator_funcdef
	: pointer direct_declarator
	{ 
	    sprintf($<str>$, "%s: POINTER TO %%s;\n",$<str>2);
	    // don't push function declarations to decl_all
	    if (fifo_empty(decl_func))
	    {
		fifo_push(decl_all, $<str>$);
	    }
	}
	| direct_declarator
	{
	    if (strlen($<str>1) > 0)
	    {
		sprintf($<str>$, "%s: %%s;\n",$<str>1);
		// don't push function declarations to decl_all
		if (fifo_empty(decl_func))
		{
		    fifo_push(decl_all, $<str>$);
		}
	    }
	}
	;

direct_declarator
	: IDENTIFIER
	| '(' declarator ')'
	{
	    //printf ("not supported direct_declerator 1 (%s)\n", $<str>2); exit(-1);
	    strcpy($<str>$, "");
	}
	| direct_declarator '[' type_qualifier_list assignment_expression ']'
	{ printf ("not supported direct_declerator 2 (%s - %s)\n", $<str>3, $<str>4); exit(-1); }
	| direct_declarator '[' type_qualifier_list ']'
	{ printf ("not supported direct_declerator 3 (%s)\n", $<str>3); exit(-1); }
	| direct_declarator '[' assignment_expression ']'
	{
		if (strlen($<str>1) > 0)
		{
			sprintf($<str>$, "%s: ARRAY[0..(%s-1)] OF %%s;\n",$<str>1, $<str>3);
		}
		else
		{
			char *p;
			p = lifo_pop(decl_all);
			sprintf($<str>1, ",0..(%s-1)] OF %%s;\n",$<str>3);
			strcpy($<str>$, p);
			strcpy(strchr($<str>$, ']'), $<str>1);
		}
		fifo_push(decl_all, $<str>$);
		strcpy($<str>$, "");
	}
	| direct_declarator '[' STATIC type_qualifier_list assignment_expression ']'
	| direct_declarator '[' type_qualifier_list STATIC assignment_expression ']'
	| direct_declarator '[' type_qualifier_list '*' ']'
	| direct_declarator '[' '*' ']'
	| direct_declarator '[' ']'
	| direct_declarator '(' parameter_type_list ')'
	{
		sprintf($<str>$, "FUNCTION %s:%%s;\n",$<str>1);
		fifo_push(decl_func, $<str>$);
		setFunctionName($<str>1);
		strcpy($<str>$, $<str>1);
//		strcpy($<str>$, "");
	}
	| direct_declarator '(' identifier_list ')'
	{
		sprintf($<str>$, "FUNCTION %s:%%s;\n",$<str>1);
		fifo_push(decl_func, $<str>$);
		setFunctionName($<str>1);
		strcpy($<str>$, $<str>1);
//		strcpy($<str>$, "");
	}
	| direct_declarator '(' ')'
	{
		sprintf($<str>$, "FUNCTION %s:%%s;\n",$<str>1);
		fifo_push(decl_func, $<str>$);
		setFunctionName($<str>1);
		strcpy($<str>$, "");
//		strcpy($<str>$, "");
	}
	;

pointer
	: '*'
	| '*' type_qualifier_list
	| '*' pointer
	| '*' type_qualifier_list pointer
	;

type_qualifier_list
	: type_qualifier
	| type_qualifier_list type_qualifier
	;


parameter_type_list
	: parameter_list
	| parameter_list ',' ELLIPSIS
	;

parameter_list
	: parameter_declaration
	| parameter_list ',' parameter_declaration
	;

parameter_declaration
	: declaration_specifiers declarator
	{
		char *p;
		while (p = fifo_pop(decl_all))
		{
//			printf(";;; %s :: %s\n\n", $<str>1, p);
			sprintf($<str>$, p, $<str>1);
			fifo_push(decl_param, $<str>$);

		}
	}
	| declaration_specifiers abstract_declarator
	| declaration_specifiers
	;

identifier_list
	: IDENTIFIER
	| identifier_list ',' IDENTIFIER
	;

type_name
	: specifier_qualifier_list
	| specifier_qualifier_list abstract_declarator
	;

abstract_declarator
	: pointer
	| direct_abstract_declarator
	| pointer direct_abstract_declarator
	;

direct_abstract_declarator
	: '(' abstract_declarator ')'
	| '[' ']'
	| '[' assignment_expression ']'
	| direct_abstract_declarator '[' ']'
	| direct_abstract_declarator '[' assignment_expression ']'
	| '[' '*' ']'
	| direct_abstract_declarator '[' '*' ']'
	| '(' ')'
	| '(' parameter_type_list ')'
	| direct_abstract_declarator '(' ')'
	| direct_abstract_declarator '(' parameter_type_list ')'
	;

initializer
	: assignment_expression
	| '{' initializer_list '}'
	| '{' initializer_list ',' '}'
	;

initializer_list
	: initializer
	| designation initializer
	| initializer_list ',' initializer
	| initializer_list ',' designation initializer
	;

designation
	: designator_list '='
	;

designator_list
	: designator
	| designator_list designator
	;

designator
	: '[' constant_expression ']'
	| '.' IDENTIFIER
	;

statement
	: labeled_statement
	| compound_statement
	| expression_statement
	| selection_statement
	| iteration_statement
	| jump_statement
	;

labeled_statement
	: IDENTIFIER ':' statement
	| CASE constant_expression ':' statement
	{ sprintf($<str>$, "%s:\n %s",$<str>2, $<str>4); }
	| DEFAULT ':' statement
	{ sprintf($<str>$, "\nELSE:\n %s",$<str>3); }
	;

compound_statement
	: '{' '}'
	| '{' block_item_list '}'
	{ sprintf($<str>$, "%s",$<str>2); }
	;

block_item_list
	: block_item
	| block_item_list block_item
	{ sprintf($<str>$, "%s %s",$<str>1, $<str>2); }
	;

block_item
	: declaration
	| statement
	  //{ printf("%s\n",$<str>1); }
	;

expression_statement
	: ';'
	| expression ';'
	{ sprintf($<str>$, "%s;\n",$<str>1); }
	;

selection_statement
	: IF '(' expression ')' statement
	{ sprintf($<str>$, "\nIF %s\n%s\nEND_IF\n",$<str>3, $<str>5); }
	| IF '(' expression ')' statement ELSE statement
	{ sprintf($<str>$, "\nIF %s\n%s\nELSE\n%s\nEND_IF\n",$<str>3, $<str>5, $<str>7); }
	| SWITCH '(' expression ')' statement
	{ sprintf($<str>$, "(*switch*)WHILE TRUE DO\nCASE %s OF\n %s\nEND_CASE\n\n(*switch*)EXIT;\n(*switch*)END_WHILE",$<str>3, $<str>5); }
	;

iteration_statement
	: WHILE '(' expression ')' statement
	{ sprintf($<str>$, "WHILE %s DO\n%s\nEND_WHILE\n",$<str>3, $<str>5); }
	| DO statement WHILE '(' expression ')' ';'
	{ sprintf($<str>$, "IF %s\n%s\nEND_IF\nWHILE %s DO\n%s\nEND_WHILE\n",$<str>5, $<str>2, $<str>5, $<str>2); }
	| FOR '(' expression_statement expression_statement ')' statement
	| FOR '(' expression_statement expression_statement expression ')' statement
	{ sprintf($<str>$, "%s\nWHILE %s DO\n%s\n%s;\nEND_WHILE\n",$<str>3, $<str>4, $<str>7, $<str>5); }
	| FOR '(' declaration expression_statement ')' statement
	| FOR '(' declaration expression_statement expression ')' statement
	;

jump_statement
	: GOTO IDENTIFIER ';'
	{ sprintf($<str>$, " %s %s;\n",$<str>1, $<str>2); }
	| CONTINUE ';'
	{ sprintf($<str>$, " %s;\n",$<str>1); }
	| BREAK ';'
	{ sprintf($<str>$, "EXIT;\n"); }
	| RETURN ';'
	{ 
		sprintf($<str>$, " RETURN;\n");
	}
	| RETURN expression ';'
	{ 
		sprintf($<str>$, " %s := (%s);\n", getFunctionName(), $<str>2);
		sprintf(TAIL($<str>$), " RETURN;\n");
	}
	;

translation_unit
	: external_declaration
	| translation_unit external_declaration
	;

external_declaration
	: function_definition
	| declaration
	;

function_definition
	: declaration_specifiers declarator_funcdef declaration_list compound_statement
	{
		printf ("not supported function_definition\n"); exit(-1);
	}
	| declaration_specifiers declarator_funcdef compound_statement
	{
		char *p;
		while( (p=fifo_pop(decl_func)) != NULL)
		{
		  printf(p, $<str>1);
		}
		while( (p=fifo_pop(decl_param)) != NULL)
		{
		  printf(p, $<str>1);
		}
		while( (p=fifo_pop(decl_all)) != NULL)
		{
		  printf(p, $<str>1);
		}
		printf("%s", $<str>3);
		printf("\nEND_FUNCTION\n");
		strcpy($<str>$, "");
	}
	;

declaration_list
	: declaration
	| declaration_list declaration
	{ sprintf($<str>$, "%s %s\n",$<str>1, $<str>2); }
	;


%%
#include <stdio.h>

extern char yytext[];
extern int column;

void yyerror(char const *s)
{
	fflush(stdout);
	printf("\n%*s\n%*s\n", column, "^", column, s);
}

int main(void)
{
    yyparse();
    return 0;
}


/* fifo implementation */
void fifo_push(fifo_entry_t type, const char *psz)
{
	unsigned int fifow_next = (s_fifos[type].write + 1) % FIFO_SIZE; 
	if (fifow_next != s_fifos[type].read)
	{
		//s_fifo[s_fifow] = psz;
		strcpy(s_fifos[type].fifo[s_fifos[type].write], psz);
		s_fifos[type].write = fifow_next;
	}
}

char *lifo_pop(fifo_entry_t type)
{
	if (s_fifos[type].read != s_fifos[type].write)
	{
		s_fifos[type].write = (s_fifos[type].write + FIFO_SIZE - 1) % FIFO_SIZE;
		return s_fifos[type].fifo[s_fifos[type].write];
	}
	return NULL;
}

char *fifo_pop(fifo_entry_t type)
{
	unsigned int fifor_prev;
	if (s_fifos[type].read != s_fifos[type].write)
	{
		fifor_prev = s_fifos[type].read;
		s_fifos[type].read = (s_fifos[type].read + 1) % FIFO_SIZE;
		return s_fifos[type].fifo[fifor_prev];
	}
	return NULL;
}

int fifo_empty(fifo_entry_t type)
{
	if (s_fifos[type].read == s_fifos[type].write)
	{
		return 1;
	}
	return 0;
}

int fifo_size(fifo_entry_t type)
{
    return ((s_fifos[type].write + FIFO_SIZE) - s_fifos[type].read) % FIFO_SIZE;
}

void fifo_tag(fifo_entry_t type)
{
	char *p;
	while ((p = fifo_pop(decl_all)) != NULL)
		fifo_push(type, p);
}

char *maptype(char *ctype)
{
	if (!strcmp(ctype, "void"))
		return "BOOL";

	if (!strcmp(ctype, "char") || !strcmp(ctype, "signed BYTE"))
		return "BYTE";
	if (!strcmp(ctype, "short") || !strcmp(ctype, "signed INT"))
		return "INT";
	if (!strcmp(ctype, "int") || !strcmp(ctype, "signed DINT"))
		return "DINT";
	if (!strcmp(ctype, "long") || !strcmp(ctype, "signed DINT"))
		return "DINT";
	if (!strcmp(ctype, "long DINT"))
		return "LINT";

	if (!strcmp(ctype, "unsigned BYTE"))
		return "UBYTE";
	if (!strcmp(ctype, "unsigned INT"))
		return "UINT";
	if (!strcmp(ctype, "unsigned DINT"))
		return "UDINT";
	if (!strcmp(ctype, "unsigned DINT"))
		return "UDINT";
	if (!strcmp(ctype, "unsigned LINT"))
		return "ULINT";
	if (!strcmp(ctype, "struct"))
		return "STRUCT";
	if (!strcmp(ctype, ""))
		return "";
//	printf("maptype: not found: %s\n", ctype);
	return ctype;
}

unsigned int genCRC(char *szData)
{
	char *p;
	unsigned int i;
	unsigned int v;
	unsigned int crc;

	i = 0;
	crc = 42; // start value
	p = szData;
	while (*p != 0)
	{
		v = crc & 0xf8000000;
		crc = crc << 5;
		crc = crc ^ (v >> 27);
		crc ^= i;
		i++;
		p++;
	}
	return crc;
}

char *genIdentifier(char *szData)
{
	static char szId[8];
	unsigned int crc;
	crc = genCRC(szData);
	sprintf(szId, "Id%u", crc);
	return szId;
}

char *strUpper(char *szStr)
{
	char *p;
	p = szStr;
	while (*p != 0)
	{
		if (*p >= 'a' && *p <= 'z')
			*p = *p - ('a' - 'A');
		p++;
	}
	return szStr;
}

int strStartsWith(const char *a, const char *b)
{
    if (strlen(b) > 0 && strncmp(a, b, strlen(b)) == 0)
	return 1;
    return 0;
}

char *strIdentifier(char *szStr)
{
	char *p;
	p = szStr;
	while (*p != 0)
	{
		if ( (*p >= 'a' && *p <= 'z')
		  || (*p >= 'A' && *p <= 'Z')
		  || (*p >= '0' && *p <= '9')
		  || (*p == '_') )
		{
			p++;
		}
		else
		{
			*p = '\0';
			return szStr;
		}
	}
	return szStr;
}

void addSym(char *szSym)
{
	int i;
	if (s_iSymTabCount >= SYM_COUNT)
	{
		DEBUG_PRINT("error: symbol table size exceeded!\n");
		exit(-1);
	}
	if (strlen(szSym) >= SYM_SIZE)
	{
		DEBUG_PRINT("error: symbol name too long '%s'!\n", szSym);
		exit(-1);
	}

	i = s_iSymTabCount++;

	DEBUG_PRINT("symbol: adding '%s' (%i)\n", szSym, i);

	strcpy(s_szSymTab[i], szSym);
}

int isSym(char *szSym)
{
	int i;
	for (i=0; i < s_iSymTabCount; i++)
	{
		DEBUG_PRINT("symbol: check %d: %s\n", i, s_szSymTab[i]);
		if (!strcmp(s_szSymTab[i], szSym))
		{
			DEBUG_PRINT("symbol: found '%s'\n", szSym);
			return 1;
		}
	}
	DEBUG_PRINT("symbol: missed '%s'\n", szSym);
	return 0;
}


void setFunctionName(char *szName)
{
	strcpy(s_szFuncName, szName);
}

char *getFunctionName(void)
{
	return s_szFuncName;
}