Blame parser.y

Packit 400c17
/*
Packit 400c17
	Copyright(C) 2016, Red Hat, Inc., Jerome Marchand
Packit 400c17
Packit 400c17
	This program is free software: you can redistribute it and/or modify
Packit 400c17
	it under the terms of the GNU General Public License as published by
Packit 400c17
	the Free Software Foundation, either version 3 of the License, or
Packit 400c17
	(at your option) any later version.
Packit 400c17
Packit 400c17
	This program is distributed in the hope that it will be useful,
Packit 400c17
	but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 400c17
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 400c17
	GNU General Public License for more details.
Packit 400c17
Packit 400c17
	You should have received a copy of the GNU General Public License
Packit 400c17
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 400c17
*/
Packit 400c17
Packit 400c17
%{
Packit 400c17
#include "parser.h"
Packit 400c17
#include <limits.h>
Packit 400c17
Packit 400c17
#include "utils.h"
Packit 400c17
Packit 400c17
#define abort(...)				\
Packit 400c17
{						\
Packit 400c17
	fprintf(stderr, __VA_ARGS__);		\
Packit 400c17
	YYABORT;				\
Packit 400c17
}
Packit 400c17
Packit 400c17
#define check_and_free_keyword(identifier, expected)			\
Packit 400c17
{									\
Packit 400c17
	if (strcmp(identifier, expected))				\
Packit 400c17
		abort("Wrong keyword: %s expected, %s received\n",	\
Packit 400c17
		      expected, identifier);				\
Packit 400c17
	free(identifier);						\
Packit 400c17
}
Packit 400c17
Packit 400c17
Packit 400c17
%}
Packit 400c17
Packit 400c17
%union {
Packit 400c17
	int i;
Packit 400c17
	unsigned int ui;
Packit 400c17
	long l;
Packit 400c17
	unsigned long ul;
Packit 400c17
	void *ptr;
Packit 400c17
	char *str;
Packit 400c17
	obj_t *obj;
Packit 400c17
	obj_list_head_t *list;
Packit 400c17
}
Packit 400c17
Packit 400c17
%token <str> IDENTIFIER STRING SRCFILE
Packit 400c17
%token 
    CONSTANT
Packit 400c17
Packit 400c17
%token NEWLINE
Packit 400c17
%token TYPEDEF
Packit 400c17
%token CONST VOLATILE
Packit 400c17
%token STRUCT UNION ENUM ELLIPSIS
Packit 400c17
%token VERSION_KW CU_KW FILE_KW STACK_KW SYMBOL_KW_NL
Packit 400c17
%token ARROW UNKNOWN_FIELD
Packit 400c17
Packit 400c17
%type <str> type_qualifier
Packit 400c17
%type <obj> typed_type base_type reference_file array_type
Packit 400c17
%type <obj> type ptr_type variable_var_list func_type elt enum_elt enum_type
Packit 400c17
%type <obj> union_type struct_type struct_elt
Packit 400c17
%type <obj> declaration_var declaration_typedef declaration
Packit 400c17
%type <obj> kabi_dw_file symbol
Packit 400c17
%type <obj> asm_symbol weak_symbol
Packit 400c17
%type <list> elt_list arg_list enum_list struct_list
Packit 400c17
%type 
    alignment
Packit 400c17
Packit 400c17
%parse-param {obj_t **root}
Packit 400c17
Packit 400c17
%%
Packit 400c17
Packit 400c17
kabi_dw_file:
Packit 400c17
	fmt_version header SYMBOL_KW_NL symbol
Packit 400c17
	{
Packit 400c17
		$$ = *root = $symbol;
Packit 400c17
		obj_fill_parent(*root);
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
fmt_version:
Packit 400c17
	VERSION_KW CONSTANT '.' CONSTANT NEWLINE
Packit 400c17
	{
Packit 400c17
		if (($2 != FILEFMT_VERSION_MAJOR) |
Packit 400c17
		    ($4 > FILEFMT_VERSION_MINOR))
Packit 400c17
			abort("Unsupported file version: %lu.%lu\n", $2, $4);
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
header:
Packit 400c17
	/* empty */
Packit 400c17
	| header header_field
Packit 400c17
	;
Packit 400c17
Packit 400c17
header_field:
Packit 400c17
	cu_field
Packit 400c17
	| source_file_field
Packit 400c17
	| stack_field
Packit 400c17
	| UNKNOWN_FIELD
Packit 400c17
	;
Packit 400c17
Packit 400c17
cu_field:
Packit 400c17
	CU_KW STRING NEWLINE
Packit 400c17
	{
Packit 400c17
	    free($STRING);
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
source_file_field:
Packit 400c17
	FILE_KW SRCFILE ':' CONSTANT NEWLINE
Packit 400c17
	{
Packit 400c17
	    free($SRCFILE);
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
stack_field:
Packit 400c17
	STACK_KW NEWLINE stack_list
Packit 400c17
	;
Packit 400c17
Packit 400c17
stack_list:
Packit 400c17
	/* empty */
Packit 400c17
	| stack_list stack_elt NEWLINE
Packit 400c17
	;
Packit 400c17
Packit 400c17
stack_elt:
Packit 400c17
	ARROW STRING
Packit 400c17
	{
Packit 400c17
		free($STRING);
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
symbol:
Packit 400c17
	declaration NEWLINE
Packit 400c17
	{
Packit 400c17
		$$ = $declaration;
Packit 400c17
	}
Packit 400c17
	| alignment declaration NEWLINE
Packit 400c17
	{
Packit 400c17
		$$ = $declaration;
Packit 400c17
		$$->alignment = $alignment;
Packit 400c17
	}
Packit 400c17
Packit 400c17
alignment:
Packit 400c17
        IDENTIFIER CONSTANT NEWLINE
Packit 400c17
	{
Packit 400c17
		check_and_free_keyword($IDENTIFIER, "Alignment");
Packit 400c17
		$$ = $CONSTANT;
Packit 400c17
	}
Packit 400c17
Packit 400c17
/* Possible types are struct union enum func typedef and var */
Packit 400c17
declaration:
Packit 400c17
	struct_type
Packit 400c17
	| union_type
Packit 400c17
	| enum_type
Packit 400c17
	| func_type
Packit 400c17
	| declaration_typedef
Packit 400c17
	| declaration_var
Packit 400c17
	| weak_symbol
Packit 400c17
	| asm_symbol
Packit 400c17
	;
Packit 400c17
Packit 400c17
declaration_typedef:
Packit 400c17
	TYPEDEF IDENTIFIER NEWLINE type
Packit 400c17
	{
Packit 400c17
	    $$ = obj_typedef_new_add($IDENTIFIER, $type);
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
declaration_var:
Packit 400c17
	IDENTIFIER IDENTIFIER type
Packit 400c17
	{
Packit 400c17
	    check_and_free_keyword($1, "var");
Packit 400c17
	    $$ = obj_var_new_add($2, $type);
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
type:
Packit 400c17
	base_type
Packit 400c17
	| reference_file
Packit 400c17
	| struct_type
Packit 400c17
	| union_type
Packit 400c17
	| enum_type
Packit 400c17
	| func_type
Packit 400c17
	| ptr_type
Packit 400c17
	| array_type
Packit 400c17
	| typed_type
Packit 400c17
	;
Packit 400c17
Packit 400c17
struct_type:
Packit 400c17
	STRUCT IDENTIFIER '{' NEWLINE '}'
Packit 400c17
	{
Packit 400c17
	    $$ = obj_struct_new($IDENTIFIER);
Packit 400c17
	}
Packit 400c17
	| STRUCT IDENTIFIER '{' NEWLINE struct_list NEWLINE '}'
Packit 400c17
	{
Packit 400c17
	    $$ = obj_struct_new($IDENTIFIER);
Packit 400c17
	    $$->member_list = $struct_list;
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
struct_list:
Packit 400c17
	struct_elt
Packit 400c17
	{
Packit 400c17
	    $$ = obj_list_head_new($struct_elt);
Packit 400c17
	}
Packit 400c17
	| struct_list NEWLINE struct_elt
Packit 400c17
	{
Packit 400c17
	    obj_list_add($1, $struct_elt);
Packit 400c17
	    $$ = $1;
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
struct_elt:
Packit 400c17
	CONSTANT IDENTIFIER type
Packit 400c17
	{
Packit 400c17
	    $$ = obj_struct_member_new_add($IDENTIFIER, $type);
Packit 400c17
	    $$->offset = $CONSTANT;
Packit 400c17
	}
Packit 400c17
	/* with alignment */
Packit 400c17
	| CONSTANT CONSTANT IDENTIFIER type
Packit 400c17
	{
Packit 400c17
	    $$ = obj_struct_member_new_add($IDENTIFIER, $type);
Packit 400c17
	    $$->offset = $1;
Packit 400c17
            $$->alignment = $2;
Packit 400c17
	}
Packit 400c17
	| CONSTANT ':' CONSTANT '-' CONSTANT IDENTIFIER type
Packit 400c17
	{
Packit 400c17
	    if ($5 > UCHAR_MAX || $3 > $5)
Packit 400c17
		abort("Invalid offset: %lx:%lu:%lu\n", $1, $3, $5);
Packit 400c17
	    $$ = obj_struct_member_new_add($IDENTIFIER, $type);
Packit 400c17
	    $$->offset = $1;
Packit 400c17
	    $$->is_bitfield = 1;
Packit 400c17
	    $$->first_bit = $3;
Packit 400c17
	    $$->last_bit = $5;
Packit 400c17
	}
Packit 400c17
	/* with alignment */
Packit 400c17
	| CONSTANT ':' CONSTANT '-' CONSTANT CONSTANT IDENTIFIER type
Packit 400c17
	{
Packit 400c17
	    if ($5 > UCHAR_MAX || $3 > $5)
Packit 400c17
		abort("Invalid offset: %lx:%lu:%lu\n", $1, $3, $5);
Packit 400c17
	    $$ = obj_struct_member_new_add($IDENTIFIER, $type);
Packit 400c17
	    $$->offset = $1;
Packit 400c17
	    $$->is_bitfield = 1;
Packit 400c17
	    $$->first_bit = $3;
Packit 400c17
	    $$->last_bit = $5;
Packit 400c17
	    $$->alignment = $6;
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
union_type:
Packit 400c17
	UNION IDENTIFIER '{' NEWLINE '}'
Packit 400c17
	{
Packit 400c17
	    $$ = obj_union_new($IDENTIFIER);
Packit 400c17
	}
Packit 400c17
	| UNION IDENTIFIER '{' NEWLINE elt_list NEWLINE '}'
Packit 400c17
	{
Packit 400c17
	    $$ = obj_union_new($IDENTIFIER);
Packit 400c17
	    $$->member_list = $elt_list;
Packit 400c17
	    $elt_list->object = $$;
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
enum_type:
Packit 400c17
	ENUM IDENTIFIER '{' NEWLINE enum_list NEWLINE '}'
Packit 400c17
	{
Packit 400c17
	    $$ = obj_enum_new($IDENTIFIER);
Packit 400c17
	    $$->member_list = $enum_list;
Packit 400c17
	    $enum_list->object = $$;
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
enum_list:
Packit 400c17
	enum_elt
Packit 400c17
	{
Packit 400c17
	    $$ = obj_list_head_new($enum_elt);
Packit 400c17
	}
Packit 400c17
	| enum_list NEWLINE enum_elt
Packit 400c17
	{
Packit 400c17
	    obj_list_add($1, $enum_elt);
Packit 400c17
	    $$ = $1;
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
enum_elt:
Packit 400c17
	IDENTIFIER '=' CONSTANT
Packit 400c17
	{
Packit 400c17
	    $$ = obj_constant_new($IDENTIFIER);
Packit 400c17
	    $$->constant = $CONSTANT;
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
func_type:
Packit 400c17
	IDENTIFIER IDENTIFIER '(' NEWLINE arg_list ')' NEWLINE type
Packit 400c17
	{
Packit 400c17
	    check_and_free_keyword($1, "func");
Packit 400c17
	    $$ = obj_func_new_add($2, $type);
Packit 400c17
	    $$->member_list = $arg_list;
Packit 400c17
	    if ($arg_list)
Packit 400c17
		    $arg_list->object = $$;
Packit 400c17
	}
Packit 400c17
	| IDENTIFIER reference_file /* protype define as typedef */
Packit 400c17
	{
Packit 400c17
	    check_and_free_keyword($IDENTIFIER, "func");
Packit 400c17
	    $$ = obj_func_new_add(NULL, $reference_file);
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
arg_list:
Packit 400c17
	/* empty */
Packit 400c17
	{
Packit 400c17
	    $$ = NULL;
Packit 400c17
	}
Packit 400c17
	| elt_list NEWLINE
Packit 400c17
	{
Packit 400c17
	    $$ = $elt_list;
Packit 400c17
	}
Packit 400c17
	| elt_list NEWLINE variable_var_list NEWLINE
Packit 400c17
	{
Packit 400c17
	    obj_list_add($elt_list, $variable_var_list);
Packit 400c17
	    $$ = $elt_list;
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
variable_var_list:
Packit 400c17
	IDENTIFIER ELLIPSIS
Packit 400c17
	{
Packit 400c17
	    /* TODO: there may be a better solution */
Packit 400c17
	    $$ = obj_var_new_add(NULL, obj_basetype_new(strdup("...")));
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
elt_list:
Packit 400c17
	elt
Packit 400c17
	{
Packit 400c17
	    $$ = obj_list_head_new($elt);
Packit 400c17
	}
Packit 400c17
	| elt_list NEWLINE elt
Packit 400c17
	{
Packit 400c17
	    obj_list_add($1, $elt);
Packit 400c17
	    $$ = $1;
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
elt:
Packit 400c17
	IDENTIFIER type
Packit 400c17
	{
Packit 400c17
	    $$ = obj_var_new_add($IDENTIFIER, $type);
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
ptr_type:
Packit 400c17
	'*' type
Packit 400c17
	{
Packit 400c17
	    $$ = obj_ptr_new_add($type);
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
array_type:
Packit 400c17
        '['CONSTANT ']' type
Packit 400c17
	{
Packit 400c17
	    $$ = obj_array_new_add($type);
Packit 400c17
	    $$->index = $CONSTANT;
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
typed_type:
Packit 400c17
	type_qualifier type
Packit 400c17
	{
Packit 400c17
	    $$ = obj_qualifier_new_add($type);
Packit 400c17
	    $$->base_type = $type_qualifier;
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
type_qualifier:
Packit 400c17
	CONST
Packit 400c17
	{
Packit 400c17
	    debug("Qualifier: const\n");
Packit 400c17
	    $$ = strdup("const");
Packit 400c17
	}
Packit 400c17
	| VOLATILE
Packit 400c17
	{
Packit 400c17
	    debug("Qualifier: volatile\n");
Packit 400c17
	    $$ = strdup("volatile");
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
base_type:
Packit 400c17
	STRING
Packit 400c17
	{
Packit 400c17
	    debug("Base type: %s\n", $STRING);
Packit 400c17
	    $$ = obj_basetype_new($STRING);
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
reference_file:
Packit 400c17
	'@' STRING
Packit 400c17
	{
Packit 400c17
	    $$ = obj_reffile_new();
Packit 400c17
	    $$->base_type = $STRING;
Packit 400c17
	    }
Packit 400c17
	;
Packit 400c17
Packit 400c17
asm_symbol:
Packit 400c17
	IDENTIFIER IDENTIFIER
Packit 400c17
	{
Packit 400c17
		check_and_free_keyword($1, "assembly");
Packit 400c17
		$$ = obj_assembly_new($2);
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
weak_symbol:
Packit 400c17
        IDENTIFIER IDENTIFIER ARROW IDENTIFIER
Packit 400c17
	{
Packit 400c17
		check_and_free_keyword($1, "weak");
Packit 400c17
		$$ = obj_weak_new($2);
Packit 400c17
		$$->link = $4;
Packit 400c17
	}
Packit 400c17
	;
Packit 400c17
Packit 400c17
Packit 400c17
%%
Packit 400c17
Packit 400c17
extern void usage(void);
Packit 400c17
Packit 400c17
obj_t *obj_parse(FILE *file, char *fn) {
Packit 400c17
	obj_t *root = NULL;
Packit 400c17
Packit 400c17
#ifdef DEBUG
Packit 400c17
	yydebug = 1;
Packit 400c17
#else
Packit 400c17
	yydebug = 0;
Packit 400c17
#endif
Packit 400c17
Packit 400c17
	yyin = file;
Packit 400c17
	yyparse(&root);
Packit 400c17
	if (!root)
Packit 400c17
		fail("No object build for file %s\n", fn);
Packit 400c17
Packit 400c17
	return root;
Packit 400c17
}
Packit 400c17
Packit 400c17
int yyerror(obj_t **root, char *s)
Packit 400c17
{
Packit 400c17
	fprintf(stderr, "error: %s\n", s);
Packit 400c17
	return 0;
Packit 400c17
}