/*
* aegis - project change supervisor
* Copyright (C) 1991-1994, 1997-1999, 2001-2008, 2012 Peter Miller
* Copyright (C) 2007 Walter Franzini
*
* This program 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 3 of the License, or (at
* your option) any later version.
*
* This program 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 this program. If not, see .
*/
%{
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef DEBUG
#define YYDEBUG 1
extern int yydebug;
#define fprintf lex_debug_fprintf
#endif
%}
%token BOOLEAN
%token BOOLEAN_CONSTANT
%token HIDE_IF_DEFAULT
%token INCLUDE
%token INTEGER
%token INTEGER_CONSTANT
%token NAME
%token REAL
%token REDEFINITION_OK
%token SHOW_IF_DEFAULT
%token STRING
%token STRING_CONSTANT
%token TIME
%token TYPE
%union
{
nstring *lv_string;
long lv_integer;
type::pointer *lv_type;
}
%type NAME STRING_CONSTANT
%type INTEGER_CONSTANT attributes
%type type structure list enumeration enum_list_begin
%{
struct name_ty
{
name_ty() : parent(0), global_flag(false) { }
name_ty *parent;
nstring name_short;
nstring name_long;
type::pointer name_type;
bool global_flag;
nstring comment;
nstring position;
bool
global()
const
{
trace(("name_short = %s, global() -> %d\n",
name_short.quote_c().c_str(), global_flag));
return global_flag;
}
};
static name_ty *current;
static symtab typedef_symtab;
static generator::pointer gen;
static bool
check_name_ne(const nstring &name, const nstring &verboten)
{
if (name == verboten)
{
}
return false;
}
static void
check_name(const nstring &name)
{
static const char *suffixes[] =
{
"_",
"_get",
"_is_set",
"_set",
"_is_set_flag",
"_introspector_factory",
};
for (const char **spp = suffixes; spp < ENDOF(suffixes); ++spp)
{
nstring suffix(*spp);
if (name.ends_with(suffix))
{
yyerror("names may not end with %s", suffix.quote_c().c_str());
return;
}
}
static const char *avoids[] =
{
"clone",
"create",
"create_from_file",
"introspector_factory",
"list",
"pointer",
"report_init",
"trace_print",
"write",
"write_file",
"write_xml",
};
for (const char **app = avoids; app < ENDOF(avoids); ++app)
{
nstring avoid(*app);
if (name == avoid)
{
yyerror("may not use %s as a name", name.quote_c().c_str());
return;
}
}
}
static void
push_name(const nstring &s)
{
trace(("push_name(s = %s)\n{\n", s.quote_c().c_str()));
name_ty *np = new name_ty;
np->name_short = s;
np->name_long = current->name_long + "_" + s;
np->parent = current;
np->global_flag = current && current->global_flag;
np->comment = lex_comment_get();
np->position = lex_position_get();
current = np;
trace(("}\n"));
}
static void
push_name_abs(const nstring &s)
{
trace(("push_name_abs(s = %s)\n{\n", s.quote_c().c_str()));
name_ty *np = new name_ty;
np->name_short = s;
np->name_long = s;
np->parent = current;
np->global_flag = true;
np->comment = lex_comment_get();
np->position = lex_position_get();
current = np;
trace(("}\n"));
}
static void
pop_name(void)
{
trace(("pop_name()\n{\n"));
name_ty *np = current;
current = np->parent;
delete np;
trace(("}\n"));
}
static void
define_type(const type::pointer &defined_type)
{
trace(("define_type(defined_type = %p)\n{\n", defined_type.get()));
defined_type->gen_body();
trace(("}\n"));
}
void
parse(const generator::pointer &g, const nstring &definition_file)
{
extern int yyparse(void);
/*
* initial name is the basename of the definition file
*/
trace(("parse(def = %s)\n{\n", definition_file.quote_c().c_str()));
#ifdef DEBUG
yydebug = trace_pretest_;
#endif
gen = g;
lex_open(definition_file);
nstring s = generator::base_name(definition_file);
check_name(s);
push_name_abs(s);
current->global_flag = false;
/*
* parse the definition file
*/
trace(("yyparse()\n{\n"));
yyparse();
trace(("}\n"));
lex_close();
/*
* emit a structure containing its fields
*/
current->name_type->toplevel();
define_type(current->name_type);
/*
* Emit code to read and write files of the top-level type.
*/
define_type(gen->top_level_factory(current->name_type));
/*
* generate the output
*/
gen->generate_file();
/*
* Release all the resources.
*/
pop_name();
gen.reset();
(typedef_symtab).clear();
trace(("}\n"));
}
%}
%%
description
: typedef_list field_list
;
typedef_list
: /* empty */
| typedef_list typedef
;
typedef
: TYPE type_name '=' type ';'
{
type::pointer tp = *$4;
delete $4;
tp->typedef_set();
typedef_symtab.assign(current->name_long, tp);
if (lex_in_include_file())
tp->in_include_file();
pop_name();
}
| '#' INCLUDE STRING_CONSTANT
{
nstring filename = *$3;
delete $3;
lex_open(filename);
}
| error
;
type_name
: NAME
{
nstring name = *$1;
delete $1;
check_name(name);
push_name_abs(name);
}
;
field
: field_name '=' type attributes ';'
{
type::pointer tp = *$3;
delete $3;
int attributes = $4;
current->parent->name_type->member_add
(
nstring(current->name_short),
tp,
attributes,
current->comment
);
pop_name();
}
| field_name error
{
pop_name();
}
;
field_name
: NAME
{
nstring name = *$1;
delete $1;
check_name(name);
push_name(name);
}
;
type
: STRING
{
type::pointer tp = gen->type_string_factory();
define_type(tp);
$$ = new type::pointer(tp);
}
| BOOLEAN
{
type::pointer tp = gen->type_boolean_factory();
define_type(tp);
$$ = new type::pointer(tp);
}
| INTEGER
{
type::pointer tp = gen->type_integer_factory();
define_type(tp);
$$ = new type::pointer(tp);
}
| REAL
{
type::pointer tp = gen->type_real_factory();
define_type(tp);
$$ = new type::pointer(tp);
}
| TIME
{
type::pointer tp = gen->type_time_factory();
define_type(tp);
$$ = new type::pointer(tp);
}
| NAME
{
nstring name = *$1;
delete $1;
type::pointer tp = typedef_symtab.get(name);
if (!tp)
{
yyerror("type \"%s\" undefined", name.c_str());
tp = gen->type_integer_factory();
}
$$ = new type::pointer(tp);
}
| structure
{
$$ = $1;
define_type(*$$);
}
| list
{
$$ = $1;
define_type(*$$);
}
| enumeration
{
$$ = $1;
define_type(*$$);
}
;
structure
: '{' field_list '}'
{
$$ = new type::pointer(current->name_type);
}
;
field_list
: /* empty */
{
current->name_type =
gen->type_structure_factory
(
current->name_long,
current->global()
);
current->name_type->comment_set(current->comment);
}
| field_list field
;
list
: '[' type ']'
{
type::pointer subtype = *$2;
delete $2;
push_name("list");
type::pointer tp =
gen->type_list_factory
(
current->name_long,
current->global(),
subtype
);
pop_name();
$$ = new type::pointer(tp);
}
;
enumeration
: '(' enum_list_begin enum_list optional_comma ')'
{
$$ = $2;
}
;
enum_list_begin
: /* empty */
{
type::pointer tp =
gen->type_enum_factory(current->name_long, current->global());
current->name_type = tp;
$$ = new type::pointer(tp);
}
;
enum_list
: enum_name
| enum_list ',' enum_name
;
enum_name
: NAME
{
nstring name = *$1;
delete $1;
push_name(name);
current->parent->name_type->member_add
(
nstring(current->name_short),
type::pointer(),
1,
current->comment
);
pop_name();
}
;
optional_comma
: /* empty */
| ','
;
attributes
: /* empty */
{ $$ = 0; }
| attributes REDEFINITION_OK
{ $$ = $1 | ATTRIBUTE_REDEFINITION_OK; }
| attributes SHOW_IF_DEFAULT
{ $$ = $1 | ATTRIBUTE_SHOW_IF_DEFAULT; }
| attributes HIDE_IF_DEFAULT
{ $$ = $1 | ATTRIBUTE_HIDE_IF_DEFAULT; }
;
/* vim: set ts=8 sw=4 et : */