From 51b4b0966ec08e8b68d030e13810a827772f869c Mon Sep 17 00:00:00 2001 From: Lauri Alanko Date: Thu, 19 Nov 1998 22:36:44 +0000 Subject: [PATCH] Again modified the formatting stuff. Some preliminary header stuff. Soon moving to use cpp.. --- tools/gcg/ChangeLog | 5 + tools/gcg/Makefile.am | 4 +- tools/gcg/db.c | 77 +++------ tools/gcg/gcg.c | 32 ++-- tools/gcg/gcg.h | 37 ++-- tools/gcg/gimpimage.def | 67 +++----- tools/gcg/lexer.l | 9 +- tools/gcg/marshall.c | 10 +- tools/gcg/output.c | 126 +++++++++----- tools/gcg/output.h | 11 +- tools/gcg/output_enum.c | 8 +- tools/gcg/output_flags.c | 17 +- tools/gcg/output_object.c | 137 +++++++-------- tools/gcg/parser.y | 129 ++++++++++---- tools/gcg/pnode.c | 344 +++++++++++++++++++++++--------------- tools/gcg/pnode.h | 9 +- 16 files changed, 581 insertions(+), 441 deletions(-) diff --git a/tools/gcg/ChangeLog b/tools/gcg/ChangeLog index 04cf76a3e6..a18164b0cb 100644 --- a/tools/gcg/ChangeLog +++ b/tools/gcg/ChangeLog @@ -1,3 +1,8 @@ +1998-11-20 Lauri Alanko + + * Again modified the formatting stuff. Some preliminary header + stuff. Soon moving to use cpp.. + 1998-11-18 Lauri Alanko * Signal marshalling should be pretty complete now. Demarshalling diff --git a/tools/gcg/Makefile.am b/tools/gcg/Makefile.am index 87658449df..dfd8c54f57 100644 --- a/tools/gcg/Makefile.am +++ b/tools/gcg/Makefile.am @@ -1,8 +1,8 @@ noinst_PROGRAMS = gcg -CFLAGS=-I/usr/local/lib/glib/include -DYYDEBUG=1 -g -Wall -W -DCPP="$(CPP)" -INCLUDES = -DYYDEBUG=1 @GLIB_CFLAGS@ +CFLAGS=-g -Wall -W -DCPP="$(CPP)" -ansi -pedantic +INCLUDES = @GLIB_CFLAGS@ YFLAGS = -d -v 2>/dev/null LIBS = @GLIB_LIBS@ diff --git a/tools/gcg/db.c b/tools/gcg/db.c index a2bbde2fd4..66842a98a2 100644 --- a/tools/gcg/db.c +++ b/tools/gcg/db.c @@ -1,72 +1,47 @@ #include "gcg.h" -static GHashTable* module_hash; +static GHashTable* package_hash = NULL; +static GSList* def_list = NULL; + void init_db(void){ - module_hash=g_hash_table_new(NULL, NULL); + package_hash = g_hash_table_new(NULL, NULL); } -PrimType* get_type(Id modname, Id name){ - Module* m = get_mod(modname); - PrimType* p = g_hash_table_lookup(m->decl_hash, name); - if(!p){ - p=g_new(PrimType, 1); - p->module=m; - p->name=name; - p->kind=TYPE_INVALID; - p->decl_header=NULL; - p->def_header=NULL; - p->definition=NULL; - g_hash_table_insert(m->decl_hash, name, p); - } - return p; +PrimType* get_type(Package* pkg, Id name){ + return g_hash_table_lookup(pkg->type_hash, name); +} + +void put_type(PrimType* t){ + g_hash_table_insert(t->module->package->type_hash, + (gpointer)t->name, t); } void put_def(Def* d){ - PrimType* t=d->type; - g_assert(t); - t->definition=d; + def_list = g_slist_append (def_list, d); } -Def* get_def(Id modname, Id type){ - PrimType* t=get_type(modname, type); - g_assert(t); - return t->definition; +Package* get_pkg(Id pkgname){ + return g_hash_table_lookup(package_hash, pkgname); } -Module* get_mod(Id modname){ - Module* m=g_hash_table_lookup(module_hash, modname); - if(!m){ - m=g_new(Module, 1); - m->name=modname; - m->decl_hash=g_hash_table_new(NULL, NULL); - m->common_header=NULL; - g_hash_table_insert(module_hash, modname, m); - } - return m; +void put_pkg(Package* pkg){ + g_hash_table_insert(package_hash, (gpointer)pkg->name, pkg); } -typedef struct{ - DefFunc f; - gpointer user_data; -}DFEdata; - -void dfe_bar(gpointer key, gpointer p, gpointer foo){ - PrimType* t=p; - DFEdata* d=foo; - if(t->definition) - (d->f)(t->definition, d->user_data); +Module* get_mod(Package* pkg, Id modname){ + return g_hash_table_lookup(pkg->mod_hash, modname); } - -void dfe_foo(gpointer key, gpointer p, gpointer dfed){ - Module* m=p; - g_hash_table_foreach(m->decl_hash, dfe_bar, dfed); +void put_mod(Module* m){ + g_hash_table_insert(m->package->mod_hash, (gpointer)m->name, m); } void foreach_def(DefFunc f, gpointer user_data){ - DFEdata d={f,user_data}; - g_hash_table_foreach(module_hash, dfe_foo, &d); -}; - + GSList* l = def_list; + while(l){ + f(l->data, user_data); + l = l->next; + } +} diff --git a/tools/gcg/gcg.c b/tools/gcg/gcg.c index ed2f82368a..23bab01c1b 100644 --- a/tools/gcg/gcg.c +++ b/tools/gcg/gcg.c @@ -2,9 +2,17 @@ #include "parser.h" #include #include + +#define __USE_POSIX2 + #include #include "output.h" +#ifndef CPP +#define CPP "cpp" +#endif + + Type* type_gtk_type; Id func_hdr_name; @@ -54,11 +62,6 @@ void output_cb(Def* def, gpointer out){ int main(int argc, char* argv[]){ /* target=stdout;*/ PRoot* out=pr_new(); - const gchar* tag_type="type"; - const gchar* tag_source="source"; - const gchar* tag_source_head="source_head"; - const gchar* tag_functions="functions"; - const gchar* tag_protected="protected"; FILE* f; init_db(); @@ -67,23 +70,20 @@ int main(int argc, char* argv[]){ yyin=fopen(argv[optind], "r"); g_assert(yyin); yyparse(); - type_gtk_type=g_new(Type, 1); - type_gtk_type->is_const=FALSE; - type_gtk_type->indirection=0; - type_gtk_type->notnull=FALSE; - type_gtk_type->prim=get_type(GET_ID("Gtk"), GET_ID("Type")); - g_assert(type_gtk_type->prim); foreach_def(output_cb, out); f=fopen(type_hdr_name, "w+"); - pr_write(out, f, &tag_type, 1); + pr_write(out, f, "type"); f=fopen(source_name, "w+"); - pr_write(out, f, &tag_source_head, 1); - pr_write(out, f, &tag_source, 1); + pr_write(out, f, "source_deps"); + pr_write(out, f, "source_head"); + pr_write(out, f, "source"); f=fopen(func_hdr_name, "w+"); - pr_write(out, f, &tag_functions, 1); + pr_write(out, f, "func_deps"); + pr_write(out, f, "functions"); f=fopen(prot_hdr_name, "w+"); - pr_write(out, f, &tag_protected, 1); + pr_write(out, f, "prot_deps"); + pr_write(out, f, "protected"); return 0; } diff --git a/tools/gcg/gcg.h b/tools/gcg/gcg.h index d11d75b7d6..1c43511583 100644 --- a/tools/gcg/gcg.h +++ b/tools/gcg/gcg.h @@ -23,6 +23,7 @@ typedef struct _MemberClass MemberClass; typedef struct _DefClass DefClass; typedef struct _Param Param; typedef struct _Module Module; +typedef struct _Package Package; typedef enum{ TYPE_INVALID, @@ -36,19 +37,23 @@ typedef enum{ TYPE_OBJECT } TypeKind; -struct _Module { +struct _Package { Id name; - Id common_header; - GHashTable* decl_hash; + GHashTable* type_hash; + GHashTable* mod_hash; }; +struct _Module { + Package* package; + Id name; + Id header; +}; + + struct _PrimType { Module* module; Id name; TypeKind kind; - Id decl_header; - Id def_header; - Def* definition; }; struct _Type { @@ -114,7 +119,7 @@ typedef enum _EmitDef{ typedef enum _MemberType{ MEMBER_DATA, - MEMBER_METHOD, + MEMBER_METHOD } MemberType; typedef enum _DataMemberKind{ @@ -168,18 +173,14 @@ typedef void (*DefFunc)(Def* def, gpointer user_data); void init_db(void); -void put_decl(PrimType* t); + +PrimType* get_type(Package* pkg, Id type); +void put_type(PrimType* t); +Package* get_pkg(Id pkgname); +void put_pkg(Package* pkg); +Module* get_mod(Package* pkg, Id module); +void put_mod(Module* m); void put_def(Def* d); -PrimType* get_type(Id module, Id type); -Def* get_def(Id module, Id type); -Module* get_mod(Id module); void foreach_def(DefFunc f, gpointer user_data); - - - -extern Type* type_gtk_type; - - - #endif diff --git a/tools/gcg/gimpimage.def b/tools/gcg/gimpimage.def index f0af7bedb3..b26ea2a513 100644 --- a/tools/gcg/gimpimage.def +++ b/tools/gcg/gimpimage.def @@ -1,42 +1,21 @@ // this is just a simple test input file -module g { - @int int; -}; +#include -module Gtk { - @int Type; -}; - -module Gimp{ - class Object; - class Layer; - class Drawable; - class Image; - enum ImageType; - enum ChannelType; - enum BaseType; -}; +module Gimp.Image; +import g; -module Gimp; - -enum ImageType{ - rgb, rgba, gray, graya, indexed, indexeda -}; -enum ChannelType{ - red, green, blue, gray, indexed, auxillary -}; -enum BaseType{ - rgb, gray, indexed -}; +enum ImageType {rgb, rgba, gray, graya, indexed, indexeda} +enum ChannelType {red, green, blue, gray, indexed, auxillary} +enum BaseType {rgb, gray, indexed} class Image : Object{ - read-only g.int width; - read-only g.int height; - g.int num-cols; + read-only int width; + read-only int height; + int num-cols; read-only BaseType base-type; - read-write g.int foobar; + read-write int foobar; read-write Layer& active-layer; read-write Layer* floating-sel; public static Image* new(g.int width, @@ -49,16 +28,16 @@ class Image : Object{ protected pre-emit void foo-4(g.int x) const; public post-emit g.int foo-5(g.int x, Drawable**& n, Image* z); public post-emit g.int foo-6(g.int a1, -g.int a2, -g.int a3, -g.int a4, -g.int a5, -g.int a6, -g.int a7, -g.int a8, -g.int a9, -g.int a10, -g.int a11, -g.int a12, -g.int a13); -}; + g.int a2, + g.int a3, + g.int a4, + int a5, + g.int a6, + g.int a7, + g.int a8, + g.int a9, + g.int a10, + g.int a11, + g.int a12, + g.int a13); +} diff --git a/tools/gcg/lexer.l b/tools/gcg/lexer.l index 2c2705e9aa..99d7af18d3 100644 --- a/tools/gcg/lexer.l +++ b/tools/gcg/lexer.l @@ -1,10 +1,12 @@ %option noyywrap +%option yylineno %{ #include "gcg.h" #include "parser.h" %} + ident [A-Za-z][A-Za-z0-9-]* header <[[:alnum:]/.]+> ws [ \n\t\r] @@ -20,6 +22,7 @@ static return T_STATIC; protected return T_PROTECTED; pre-emit return T_PRE_EMIT; post-emit return T_POST_EMIT; +mid-emit return T_DUAL_EMIT; read-only return T_READ_ONLY; read-write return T_READ_WRITE; private return T_PRIVATE; @@ -32,6 +35,7 @@ module return T_MODULE; import return T_IMPORT; header return T_HEADER; opaque return T_OPAQUE; +package return T_PACKAGE; void return T_VOID; enum return T_ENUM; @@ -39,6 +43,7 @@ flags return T_FLAGS; @int return T_INT; real return T_DOUBLE; boxed return T_BOXED; +foreign return T_FOREIGN; {ident} { @@ -56,7 +61,9 @@ boxed return T_BOXED; } {header} { - yylval.id=g_quark_to_string(g_quark_from_string(yytext)); + gchar* tmp = g_strndup(&yytext[1], yyleng-2); + yylval.id=g_quark_to_string(g_quark_from_string(tmp)); + g_free (tmp); return T_HEADERNAME; } diff --git a/tools/gcg/marshall.c b/tools/gcg/marshall.c index 2311f093c9..c7d567484d 100644 --- a/tools/gcg/marshall.c +++ b/tools/gcg/marshall.c @@ -46,7 +46,7 @@ MarshallType marshalling_type(Type* t){ SignalType* sig_type(Method* m){ SignalType *t=g_new(SignalType, 1); GSList* p=m->params, *a=NULL; - t->package = DEF(MEMBER(m)->my_class)->type->module->name; + t->package = DEF(MEMBER(m)->my_class)->type->module->package->name; t->rettype = marshalling_type(&m->ret_type); while(p){ Param* param=p->data; @@ -152,7 +152,7 @@ PNode* p_handler_type(SignalType* t){ PNode* p_signal_id(Method* s){ PrimType* t=DEF(MEMBER(s)->my_class)->type; return p_fmt("_~_~_signal_~", - p_c_ident(t->module->name), + p_c_ident(t->module->package->name), p_c_ident(t->name), p_c_ident(MEMBER(s)->name)); } @@ -219,7 +219,8 @@ PNode* p_demarshaller(SignalType* t){ gint idx=0; - return p_lst((t->rettype==TYPE_NONE) + return p_fmt("~~", + (t->rettype==TYPE_NONE) ? p_fmt("\t*(GTK_RETLOC_~(args[~])) =\n", p_gtype_name(t->rettype, FALSE), p_prf("%d", g_slist_length(t->argtypes))) @@ -228,8 +229,7 @@ PNode* p_demarshaller(SignalType* t){ "~" "\tuser_data);\n", p_cast(p_handler_type(t), p_str("func")), - p_for(t->argtypes, p_arg_demarsh, &idx)), - p_nil); + p_for(t->argtypes, p_arg_demarsh, &idx))); } diff --git a/tools/gcg/output.c b/tools/gcg/output.c index aa1edff70d..4c6d755ba4 100644 --- a/tools/gcg/output.c +++ b/tools/gcg/output.c @@ -39,18 +39,41 @@ PNode* p_c_macro(Id id){ } PNode* p_param(FunParams* p, ParamOptions* opt){ - return p_lst(opt->first ? p_nil : p_str(", "), + return p_fmt("~~~~", + opt->first ? p_nil : p_str(", "), opt->types ? p_type(&p->type) : p_nil, opt->types && opt->names ? p_str(" ") : p_nil, - opt->names ? p->name : p_nil, - NULL); + opt->names ? p->name : p_nil); +} + +PNode* p_prot_header(Module* m){ + if(m->header) + return p_str(m->header); + else + return p_fmt("~/~_p.h", + p_c_ident(m->package->name), + p_c_ident(m->name)); +} + +PNode* p_type_header(Module* m){ + if(m->header) + return p_str(m->header); + else + return p_fmt("~/~_t.h", + p_c_ident(m->package->name), + p_c_ident(m->name)); +} + +PNode* p_type_include(Module* m){ + return p_fmt("#include <~>\n", + p_type_header(m)); } PNode* p_params(FunParams* args, ParamOptions* opt){ ParamOptions o=*opt; PNode* n=p_nil; while(args){ - n=p_lst(n, p_param(args, &o), NULL); + n=p_fmt("~~", n, p_param(args, &o)); args=args->next; o.first=FALSE; } @@ -68,9 +91,9 @@ PNode* p_prim_varname(PrimType* t){ } PNode* p_primtype(PrimType* t){ - return p_lst(p_str(t->module->name), - p_str(t->name), - NULL); + return p_fmt("~~", + p_str(t->module->package->name), + p_str(t->name)); } PNode* p_cast(PNode* force_type, PNode* expression){ @@ -87,7 +110,7 @@ PNode* p_type(Type* t){ t->is_const ? p_str("const ") : p_nil, p_primtype(t->prim)); while(i--) - node=p_lst(node, p_str("*"), NULL); + node=p_fmt("~~", node, p_str("*")); /* file_add_dep(s, t->prim->decl_header);*/ return node; }else @@ -102,7 +125,7 @@ PNode* p_self_type(ObjectDef* o, PBool const_self){ PNode* p_varname(PrimType* t, PNode* name){ return p_fmt("~_~_~", - p_c_ident(t->module->name), + p_c_ident(t->module->package->name), p_c_ident(t->name), name); } @@ -125,37 +148,36 @@ PNode* p_type_guard(Type* t, PNode* var){ kind != */ - return p_lst - ((t->indirection && t->notnull - ? p_fmt("\tg_assert (~);\n", var) - : p_nil), - ((t->indirection==1 && p->kind == TYPE_OBJECT) - ? (t->notnull - ? p_fmt("\tg_assert (~(~));\n", - p_macro_name(p, "IS", NULL), - var) - : p_fmt("\tg_assert (!~ || ~(~));\n", - var, - p_macro_name(p, "IS", NULL), - var)) - : (t->indirection==0 - ? ((p->kind == TYPE_ENUM) - ? p_fmt("\tg_assert (~ <= ~);\n", - var, - p_macro_name(p, NULL, "LAST")) - : ((p->kind == TYPE_FLAGS) - ? p_fmt("\tg_assert ((~ << 1) < ~);\n", - var, - p_macro_name(p, NULL, "LAST")) - : p_nil)) - : p_nil)), - NULL); + return p_fmt("~~", + (t->indirection && t->notnull + ? p_fmt("\tg_assert (~);\n", var) + : p_nil), + ((t->indirection==1 && p->kind == TYPE_OBJECT) + ? (t->notnull + ? p_fmt("\tg_assert (~(~));\n", + p_macro_name(p, "IS", NULL), + var) + : p_fmt("\tg_assert (!~ || ~(~));\n", + var, + p_macro_name(p, "IS", NULL), + var)) + : (t->indirection==0 + ? ((p->kind == TYPE_ENUM) + ? p_fmt("\tg_assert (~ <= ~);\n", + var, + p_macro_name(p, NULL, "LAST")) + : ((p->kind == TYPE_FLAGS) + ? p_fmt("\tg_assert ((~ << 1) < ~);\n", + var, + p_macro_name(p, NULL, "LAST")) + : p_nil)) + : p_nil))); } PNode* p_type_guards(FunParams* args){ PNode* p=p_nil; while(args){ - p=p_lst(p, p_type_guard(&args->type, args->name), NULL); + p=p_fmt("~~", p, p_type_guard(&args->type, args->name)); args=args->next; } return p; @@ -164,7 +186,11 @@ PNode* p_type_guards(FunParams* args){ PNode* p_prototype(Type* rettype, PNode* name, PNode* args1, FunParams* args2){ - ParamOptions o={(!args1 || args1==p_nil), TRUE, TRUE}; + ParamOptions o; + o.first = !args1 || args1 == p_nil; + o.names = TRUE; + o.types = TRUE; + return p_fmt("~ ~ (~~)", p_type(rettype), name, @@ -176,14 +202,14 @@ void output_var_alias(PRoot* out, PrimType* t, PNode* basename){ pr_add(out, "import_alias", p_fmt("#define ~ ~_~\n", basename, - p_c_ident(t->module->name), + p_c_ident(t->module->package->name), basename)); } void output_type_alias(PRoot* out, PrimType* t, PNode* basename){ pr_add(out, "import_alias", p_fmt("typedef ~~ ~;\n", - p_str(t->module->name), + p_str(t->module->package->name), basename, basename)); } @@ -218,10 +244,10 @@ void output_func(PRoot* out, PNode* p_macro_name(PrimType* t, Id mid, Id post){ return p_fmt("~~_~~", - p_c_macro(t->module->name), - mid ? p_lst(p_str("_"), p_c_macro(mid), NULL) : p_nil, + p_c_macro(t->module->package->name), + mid ? p_fmt("_~", p_c_macro(mid)) : p_nil, p_c_macro(t->name), - post ? p_lst(p_str("_"), p_c_macro(post), NULL) : p_nil); + post ? p_fmt("_~", p_c_macro(post)) : p_nil); } void output_var(PRoot* out, Id tag, PNode* type, PNode* name){ @@ -247,11 +273,11 @@ void output_def(PRoot* out, Def* d){ pr_add(out, "protected", p_str("\n\n")); pr_add(out, "source_head", p_str("\n")); pr_add(out, "type", p_fmt("#define ~ \\\n" - " (~ ? ~ : ~())\n", + " (~ ? ~() : (void)0, ~)\n", p_macro_name(t, "TYPE", NULL), type_var, - type_var, - p_internal_varname(t, p_str("init_type")))); + p_internal_varname(t, p_str("init_type")), + type_var)); output_var(out, "type", p_str("GtkType"), type_var); @@ -270,4 +296,14 @@ void output_def(PRoot* out, Def* d){ } } - + + +/* +void add_dep(PRoot* out, Id tag, PrimType* type){ + pr_put(out, tag, type->module); +} + +PNode* p_deps(Id tag){ + return p_col(tag, p_dep, NULL); +} +*/ diff --git a/tools/gcg/output.h b/tools/gcg/output.h index f678da79e6..dd1731b901 100644 --- a/tools/gcg/output.h +++ b/tools/gcg/output.h @@ -58,6 +58,8 @@ PNode* p_guard_end(const gchar *c); PNode* p_c_ident(Id id); PNode* p_c_macro(Id id); +PNode* p_prot_header(Module* m); +PNode* p_type_header(Module* m); void output_func(PRoot* out, @@ -71,8 +73,11 @@ void output_func(PRoot* out, void output_var(PRoot* out, Id tag, PNode* type, PNode* name); void output_def(PRoot* out, Def* d); -void output_object(PRoot* out, ObjectDef* d); -void output_enum(PRoot* out, EnumDef* d); -void output_flags(PRoot* out, FlagsDef* d); +void output_object(PRoot* out, Def* d); +void output_enum(PRoot* out, Def* d); +void output_flags(PRoot* out, Def* d); +PNode* p_type_include(Module* m); + + #endif diff --git a/tools/gcg/output_enum.c b/tools/gcg/output_enum.c index ee61aea80d..3f133ad2d6 100644 --- a/tools/gcg/output_enum.c +++ b/tools/gcg/output_enum.c @@ -31,7 +31,7 @@ void output_enum_type_init(PRoot* out, EnumDef* e){ PrimType* t=DEF(e)->type; output_func(out, "type", - type_gtk_type, + NULL, p_internal_varname(t, p_str("init_type")), p_nil, NULL, @@ -39,8 +39,7 @@ void output_enum_type_init(PRoot* out, EnumDef* e){ "~" "\t\t{0, NULL, NULL}\n" "\t};\n" - "\t~ = gtk_type_register_enum (\"~\", values);\n" - "\treturn ~;\n", + "\t~ = gtk_type_register_enum (\"~\", values);\n", p_prf("%d", g_slist_length(e->alternatives)+1), p_for(e->alternatives, p_enum_value, t), p_internal_varname(t, p_str("type")), @@ -48,7 +47,8 @@ void output_enum_type_init(PRoot* out, EnumDef* e){ p_internal_varname(t, p_str("type")))); } -void output_enum(PRoot* out, EnumDef* e){ +void output_enum(PRoot* out, Def* d){ + EnumDef* e = (EnumDef*)d; output_enum_type_init(out, e); pr_add(out, "type", p_enum_decl(e)); } diff --git a/tools/gcg/output_flags.c b/tools/gcg/output_flags.c index 60bca7d53e..ec2080307b 100644 --- a/tools/gcg/output_flags.c +++ b/tools/gcg/output_flags.c @@ -13,10 +13,9 @@ PNode* p_flags_member(Id id, FlagData* d){ } PNode* p_flags_decl(FlagsDef* e){ - FlagData d={ - -1, - DEF(e)->type - }; + FlagData d; + d.i = -1; + d.t = DEF(e)->type; return p_fmt("typedef enum {\n" "~" "} ~;\n" @@ -49,8 +48,7 @@ void output_flags_type_init(PRoot* out, FlagsDef* e){ "~" "\t\t{0, NULL, NULL}\n" "\t};\n" - "\t~ = gtk_type_register_flags (\"~\", values);\n" - "\treturn ~;\n", + "\t~ = gtk_type_register_flags (\"~\", values);\n", p_prf("%d", g_slist_length(e->flags)+1), p_for(e->flags, p_flags_value, t), p_internal_varname(t, p_str("type")), @@ -58,8 +56,9 @@ void output_flags_type_init(PRoot* out, FlagsDef* e){ p_internal_varname(t, p_str("type")))); } -void output_flags(PRoot* out, FlagsDef* e){ - pr_add(out, "type", p_flags_decl(e)); - output_flags_type_init(out, e); +void output_flags(PRoot* out, Def* d){ + FlagsDef* f = (FlagsDef*) d; + pr_add(out, "type", p_flags_decl(f)); + output_flags_type_init(out, f); } diff --git a/tools/gcg/output_object.c b/tools/gcg/output_object.c index b54a615cff..26aae38eb8 100644 --- a/tools/gcg/output_object.c +++ b/tools/gcg/output_object.c @@ -130,6 +130,11 @@ void output_connector(PRoot* out, Method* m){ p_str(MEMBER(m)->name))); } +PNode* p_param_marshtype(gpointer p){ + Param* param=p; + return p_fmt(",\n\t\t~", + p_gtktype(¶m->type)); +} void output_method(PRoot* out, Method* m){ @@ -148,6 +153,7 @@ void output_method(PRoot* out, Method* m){ p_self_name(MEMBER(m)), p_nil, m->params); + switch(k){ SignalType* sig; case METH_EMIT_PRE: @@ -155,10 +161,43 @@ void output_method(PRoot* out, Method* m){ case METH_EMIT_BOTH: sig=sig_type(m); output_var(out, NULL, - p_str("GtkSignalID"), + p_str("guint"), p_signal_id(m)); o.names=FALSE; o.types=TRUE; + pr_put(out, "class_init_head", + p_fmt("\textern void ~ (GtkObject*, GtkSignalFunc, " + "gpointer, GtkArg*);\n", + p_signal_demarshaller_name(sig))); + pr_put(out, "member_class_init", + p_fmt("\t~ =\n" + "\tgtk_signal_new(\"~\",\n" + "\t\tGTK_RUN_~,\n" + "\t\tobklass->type,\n" + "\t\tGTK_SIGNAL_OFFSET (~, ~),\n" + "\t\t~,\n" + "\t\t~,\n" + "\t\t~" + "~);\n" + "\tgtk_object_class_add_signals(obklass,\n" + "\t\t&~,\n" + "\t\t1);\n" + "\t}\n", + p_signal_id(m), + p_str(MEMBER(m)->name), + p_str(m->kind==METH_EMIT_PRE + ?"FIRST" + :m->kind==METH_EMIT_POST + ?"LAST" + :"BOTH"), + p_class_name(t), + name, + p_signal_demarshaller_name(sig), + p_gtktype(&m->ret_type), + p_prf("%d", g_slist_length(m->params)), + p_for(m->params, p_param_marshtype, p_nil), + p_signal_id(m))); + pr_add(out, "functions", p_fmt("typedef ~ (*~)(~, gpointer);\n", p_type(&m->ret_type), @@ -174,20 +213,22 @@ void output_method(PRoot* out, Method* m){ o.names=TRUE; o.types=TRUE; pr_add(out, "source_head", - p_fmt("static inline ~ ~ (~);\n", + p_fmt("static ~ ~_~_real (~);\n", p_type(&m->ret_type), - p_real_varname(t, name), + p_c_ident(t->name), + name, p_params(par, &o))); o.types=FALSE; - dispatch=p_fmt("\t~ ~(~);\n", + dispatch=p_fmt("\t~~_~_real (~);\n", m->ret_type.prim? p_str("return "): p_nil, - p_real_varname(t, name), + p_c_ident(t->name), + name, p_params(par, &o)); break; case METH_VIRTUAL: - dispatch=p_fmt("\t~((~*)((GtkObject*)~)->klass)->~(~);\n", + dispatch=p_fmt("\t~((~*)((GtkObject*) ~)->klass)->~ (~);\n", m->ret_type.prim? p_str("return "): p_nil, @@ -213,7 +254,7 @@ void output_data_member(PRoot* out, DataMember* m){ PrimType* t=DEF(MEMBER(m)->my_class)->type; PNode* name = p_c_ident(MEMBER(m)->name); PNode* self = p_self_name(MEMBER(m)); - + switch(m->prot){ FunParams* par; @@ -262,6 +303,7 @@ void output_data_member(PRoot* out, DataMember* m){ } /* fall through */ case DATA_READONLY: + pr_put(out, "func_depends", m->type.prim->module); par=fparams("t", &MEMBER(m)->my_class->self_type[TRUE], self, p_nil); @@ -275,7 +317,9 @@ void output_data_member(PRoot* out, DataMember* m){ self, name)); fparams_free(par); + /* fall through */ case DATA_PROTECTED: + pr_put(out, "prot_depends", m->type.prim->module); } } @@ -307,7 +351,7 @@ void output_object_type_init(PRoot* out, ObjectDef* o){ PNode* type_var=p_internal_varname(t, p_str("type")); output_func(out, "type", - type_gtk_type, + NULL, p_internal_varname(t, p_str("init_type")), p_nil, NULL, @@ -322,8 +366,7 @@ void output_object_type_init(PRoot* out, ObjectDef* o){ "\t\tNULL,\n" "\t};\n" "\tif (!~)\n" - "\t\t~ = gtk_type_unique (~, &info);\n" - "\treturn ~;\n", + "\t\t~ = gtk_type_unique (~, &info);\n", p_primtype(t), p_primtype(t), p_class_name(t), @@ -335,67 +378,12 @@ void output_object_type_init(PRoot* out, ObjectDef* o){ type_var)); } -PNode* p_param_marshtype(gpointer p){ - Param* param=p; - return p_fmt(",\n\t\t~", - p_gtktype(¶m->type)); -} -PNode* p_member_class_init(gpointer m, gpointer o){ - ObjectDef* ob=o; - Member* mem=m; - Method* meth; - SignalType* sig; - if(mem->membertype!=MEMBER_METHOD) - return p_nil; - meth=m; - sig=sig_type(meth); - switch(meth->kind){ - case METH_EMIT_PRE: - case METH_EMIT_POST: - case METH_EMIT_BOTH: - return p_fmt("\t{\n" - "\textern void ~ (GtkObject*, GtkSignalFunc, " - "gpointer, GtkArg*);\n" - "\t~ =\n" - "\tgtk_signal_new(\"~\",\n" - "\t\tGTK_RUN_~,\n" - "\t\tobklass->type,\n" - "\t\tGTK_SIGNAL_OFFSET (~, ~),\n" - "\t\t~,\n" - "\t\t~,\n" - "\t\t~" - "~);\n" - "\tgtk_object_class_add_signals(obklass,\n" - "\t\t&~,\n" - "\t\t1);\n" - "\t}\n", - p_signal_demarshaller_name(sig), - p_signal_id(meth), - p_str(mem->name), - p_str(meth->kind==METH_EMIT_PRE - ?"FIRST" - :meth->kind==METH_EMIT_POST - ?"LAST" - :"BOTH"), - p_class_name(DEF(ob)->type), - p_c_ident(mem->name), - p_signal_demarshaller_name(sig), - p_gtktype(&meth->ret_type), - p_prf("%d", g_slist_length(meth->params)), - p_for(meth->params, p_param_marshtype, p_nil), - p_signal_id(meth)); - break; - default: - return p_nil; - break; - } - sig_type_free(sig); -} - - - void output_object_init(PRoot* out, ObjectDef* o){ + pr_add(out, "prot_deps", + p_col("prot_depends", p_type_include)); + pr_add(out, "func_deps", + p_col("func_depends", p_type_include)); pr_add(out, "source_head", p_fmt("static inline void ~ (~ ~);\n", p_varname(DEF(o)->type, p_str("init_real")), @@ -424,15 +412,18 @@ void output_class_init(PRoot* out, ObjectDef* o){ p_fmt("~* klass", p_class_name(DEF(o)->type)), NULL, - p_fmt("\tGtkObjectClass* obklass = \n" - "\t\t(GtkObjectClass*) klass;\n" + p_fmt("\tGtkObjectClass* obklass = " + "(GtkObjectClass*) klass;\n" + "~" "~" "\t~ (klass);\n", - p_for(o->members, p_member_class_init, o), + p_col("class_init_head", NULL), + p_col("member_class_init", NULL), p_varname(DEF(o)->type, p_str("class_init_real")))); } -void output_object(PRoot* out, ObjectDef* o){ +void output_object(PRoot* out, Def* d){ + ObjectDef* o = (ObjectDef*)d; output_object_type_init(out, o); output_class_init(out, o); output_object_init(out, o); diff --git a/tools/gcg/parser.y b/tools/gcg/parser.y index 267241872c..f02307b57c 100644 --- a/tools/gcg/parser.y +++ b/tools/gcg/parser.y @@ -2,14 +2,13 @@ #include "gcg.h" #define YYDEBUG 1 +static Package* current_package; static Module* current_module; -static Id current_header; static ObjectDef* current_class; -static GSList* imports; static Method* current_method; static GSList* imports_list; - + %} %union { @@ -70,12 +69,15 @@ static GSList* imports_list; %token T_DOUBLE %token T_BOXED %token T_SIGNAL +%token T_FOREIGN +%token T_PACKAGE %token T_IDENT %token T_HEADERNAME %token T_STRING %type ident +%type headerdef %type fundtype %type type %type typeorvoid @@ -108,28 +110,74 @@ start_symbol: deffile ; deffile: declarations definitions; -declarations: /* empty */ | declarations modulescope; +declarations: /* empty */ | declarations package; definitions: current_module_def deflist; deflist: /* empty */ | deflist def { put_def($2); -}; +} | deflist import; -import: T_IMPORT ident T_END { - imports=g_slist_prepend(imports, (gpointer)($2)); +import: T_IMPORT importlist T_END; + +importlist: ident { + Package* p = get_pkg($1); + if(!p) + g_error("Attempt to import unknown package %s", $1); + imports_list = g_slist_prepend(imports_list, p); +} | importlist T_COMMA ident { + Package* p = get_pkg($3); + if(!p) + g_error("Attempt to import unknown package %s", $3); + imports_list = g_slist_prepend(imports_list, p); } -modulescope: T_MODULE ident T_OPEN_B { - current_module=get_mod($2); -} decllist T_CLOSE_B { - current_module=NULL; -} T_END; - -current_module_def: T_MODULE ident T_END { - current_module=get_mod($2); +package: T_PACKAGE ident T_OPEN_B { + Package* p = get_pkg($2); + if(!p){ + p = g_new(Package, 1); + p->name = $2; + p->type_hash = g_hash_table_new(NULL, NULL); + p->mod_hash = g_hash_table_new(NULL, NULL); + put_pkg(p); + } + current_package = p; +} modulelist T_CLOSE_B { + current_package = NULL; }; +current_module_def: T_MODULE ident T_SCOPE ident T_END { + Package* p = get_pkg($2); + Module* m; + if(!p) + g_error("Unknown package %s", $2); + m = get_mod(p, $4); + if(!m) + g_error("Unknown module %s.%s", $2, $4); + current_module = m; +} + + +modulelist: /* empty */ | modulelist module; + +headerdef: /* empty */ { + $$ = NULL; +}| T_HEADERNAME; + + + +module: T_MODULE ident headerdef T_OPEN_B { + Module* m = get_mod(current_package, $2); + if(!m){ + m = g_new(Module, 1); + m->package = current_package; + m->name = $2; + m->header = $3; + put_mod(m); + } + current_module = m; +} decllist T_CLOSE_B; + decllist: /* empty */ | decllist decl; decl: simpledecl ;/* | classdecl | opaquedecl | protclassdecl;*/ @@ -148,9 +196,12 @@ fundtype: T_INT { $$ = TYPE_FLAGS; } -simpledecl: fundtype primtype T_END { - g_assert($2->kind==TYPE_INVALID); - $2->kind = $1; +simpledecl: fundtype ident T_END { + PrimType* t = g_new(PrimType, 1); + t->module = current_module; + t->name = $2; + t->kind = $1; + put_type(t); }; semitype: const_def primtype { @@ -181,9 +232,26 @@ typeorvoid: type | T_VOID { primtype: ident T_SCOPE ident { - $$ = get_type($1, $3); + Package* p=get_pkg($1); + PrimType* t; + if(!p) + g_error("Unknown package %s!", $1); + t = get_type(p, $3); + if(!t) + g_error("Unknown type %s:%s", $1, $3); + $$ = t; } | ident { - $$ = get_type(current_module->name, $1); + Package* p = current_module->package; + PrimType* t; + GSList* l = imports_list; + t = get_type(p, $1); + while(l && !t){ + t = get_type(l->data, $1); + l = l->next; + } + if(!t) + g_error("Couldn't find type %s in import list", $1); + $$ = t; }; paramlist: /* empty */ { @@ -271,22 +339,22 @@ idlist: ident { def: classdef | enumdef | flagsdef; -enumdef: T_ENUM primtype T_OPEN_B idlist T_CLOSE_B docstring T_END { +enumdef: T_ENUM primtype docstring T_OPEN_B idlist T_CLOSE_B { EnumDef* d=g_new(EnumDef, 1); g_assert($2->kind==TYPE_ENUM); - d->alternatives = $4; + d->alternatives = $5; $$=DEF(d); $$->type=$2; - $$->doc=$6; + $$->doc=$3; }; -flagsdef: T_FLAGS primtype T_OPEN_B idlist T_CLOSE_B docstring T_END { +flagsdef: T_FLAGS primtype docstring T_OPEN_B idlist T_CLOSE_B T_END { FlagsDef* d=g_new(FlagsDef, 1); g_assert($2->kind==TYPE_ENUM); - d->flags = $4; + d->flags = $5; $$=DEF(d); $$->type=$2; - $$->doc=$6; + $$->doc=$3; }; parent: /* empty */{ @@ -298,9 +366,14 @@ parent: /* empty */{ classdef: T_CLASS primtype parent docstring T_OPEN_B { g_assert($2->kind==TYPE_OBJECT); g_assert(!$3 || $3->kind==TYPE_OBJECT); + g_assert($2->module == current_module); current_class=g_new(ObjectDef, 1); -} classbody T_CLOSE_B T_END { - Type t={FALSE, 1, TRUE, $2}; +} classbody T_CLOSE_B { + Type t; + t.is_const = FALSE; + t.indirection = 1; + t.notnull = TRUE; + t.prim = $2; current_class->self_type[0]=t; t.is_const=TRUE; current_class->self_type[1]=t; diff --git a/tools/gcg/pnode.c b/tools/gcg/pnode.c index 2945eb47a8..ba3ca98b60 100644 --- a/tools/gcg/pnode.c +++ b/tools/gcg/pnode.c @@ -2,36 +2,67 @@ #include #include -const gconstpointer p_no_data = &p_no_data; static const gconstpointer p_node_magic_tag = &p_node_magic_tag; -#define BE_NODE(x) (g_assert((x) && ((PNode*)(x))->magic == &p_node_magic_tag)) + +#define BE_NODE(x) g_assert((x) && ((PNode*)(x))->magic == &p_node_magic_tag) static GMemChunk* p_node_chunk; static GList* p_float_list; static GHashTable* p_str_hash; +typedef enum{ + NODE_NIL, + NODE_DATA, + NODE_COLLECT +} PNodeType; + +typedef struct{ + gchar* str; + PNode* node; +} PBlock; + +typedef struct _PRNode{ + GQuark tag; + PNode* node; +} PRNode; + + +struct _PRoot{ + GData* data; + GList* nodes; +}; + struct _PNode{ gconstpointer magic; guint ref_count; GList* float_link; - const gchar* str; - GSList* children; + PNodeType type; + union { + struct { + gint nblocks; + PBlock* blocks; + } b; + struct { + PNodeCreateFunc func; + GQuark tag; + } c; + } u; }; static PNode p_nil_node = { &p_node_magic_tag, -1, NULL, - NULL, - NULL + NODE_NIL, + {{0,NULL}} }; PNode* p_nil = &p_nil_node; -static PNode* p_make(void){ +static PNode* p_make(PNodeType type){ PNode* node; if(!p_node_chunk) p_node_chunk = g_mem_chunk_create(PNode, 1024, @@ -41,8 +72,7 @@ static PNode* p_make(void){ node->ref_count = 0; node->magic = &p_node_magic_tag; node->float_link = p_float_list = g_list_prepend(p_float_list, node); - node->str = NULL; - node->children = NULL; + node->type = type; return node; } @@ -65,162 +95,178 @@ void p_unref(PNode* node){ node->ref_count--; if(node->ref_count>0) return; - else{ - GSList* l; - if(node->children){ - for(l = node->children;l;l = l->next) - p_unref(l->data); - g_slist_free(node->children); - } else - g_hash_table_remove(p_str_hash, node->str); - g_free((gpointer)node->str); - g_mem_chunk_free(p_node_chunk, node); + switch(node->type){ + case NODE_DATA:{ + PBlock* bl = node->u.b.blocks; + gint i=node->u.b.nblocks; + while(i--){ + g_free(bl[i].str); + p_unref(bl[i].node); + } + g_free(bl); + break; + } + case NODE_NIL: + break; + case NODE_COLLECT: + break; + } + g_mem_chunk_free(p_node_chunk, node); +} + +typedef struct{ + FILE* f; + PRoot* p; +} PWrite; + +typedef struct{ + PWrite* w; + PNode* n; +} PCollect; + +static void p_write(PNode* node, PWrite* w); + + +void cb_pwrite(gpointer key, gpointer value, gpointer data){ + PCollect* c = data; + PNodeCreateFunc func = c->n->u.c.func; + (void)key; + if(func) + p_write(func(value), c->w); + else + p_write(value, c->w); +} + + +static void p_write(PNode* node, PWrite* w){ + BE_NODE(node); + switch(node->type){ + case NODE_DATA:{ + gint i = 0, n = node->u.b.nblocks; + PBlock* bl = node->u.b.blocks; + + for(i = 0; i < n; i++){ + if(bl[i].str) + fputs(bl[i].str, w->f); + p_write(bl[i].node, w); + } + break; + } + case NODE_NIL: + break; + case NODE_COLLECT:{ + GHashTable* h = g_datalist_id_get_data(&w->p->data, + node->u.c.tag); + PCollect c; + c.w = w; + c.n = node; + if(!h) + break; + g_hash_table_foreach(h, cb_pwrite, &c); + break; + } } } -void p_write(PNode* node, FILE* f){ - GSList* l; - BE_NODE(node); - if(node==p_nil) - return; - l = node->children; - if(l){ - const gchar* c = node->str; - if(c) - while(*c){ - gint i = 0; - while(c[i] && c[i] != '~') - i++; - fwrite(c, i, 1, f); - c += i; - if(*c == '~'){ - c++; - g_assert(l); - p_write(l->data, f); - l = l->next; - } - } - else - do{ - p_write(l->data, f); - }while((l=l->next)); - }else if(node->str) - fputs(node->str, f); +static PNode* p_simple_string(gchar* str){ + PNode* n = p_make(NODE_DATA); + n->u.b.nblocks = 1; + n->u.b.blocks = g_new(PBlock, 1); + n->u.b.blocks[0].str = str; + n->u.b.blocks[0].node = p_nil; + return n; } - -void p_traverse(PNode* node, PNodeTraverseFunc func, gpointer user_data){ - GSList* l; - BE_NODE(node); - func(node, user_data); - for(l=node->children;l;l=l->next) - p_traverse(l->data, func, user_data); -} - + PNode* p_str(const gchar* str){ PNode* n; if(!p_str_hash) p_str_hash = g_hash_table_new(g_str_hash, g_str_equal); n = g_hash_table_lookup(p_str_hash, str); - if(!n){ - n = p_make(); - n->str = g_strdup(str); - g_hash_table_insert(p_str_hash, n->str, n); - } - return n; + if(n) + return n; + else + return p_simple_string(g_strdup(str)); } PNode* p_prf(const gchar* format, ...){ - PNode* n = p_make(); + PNode* n; va_list args; va_start(args, format); - n->str = g_strdup_vprintf (format, args); + n = p_simple_string(g_strdup_vprintf (format, args)); + va_end(args); return n; } PNode* p_fmt(const gchar* f, ...){ va_list args; - gchar* b = f; - PNode* n; - GSList* l = NULL; + const gchar* b; + PNode* n = p_make(NODE_DATA); + gint i; + PBlock* bl; + va_start(args, f); g_assert(f); - while(*f){ - while(*f && *f != '~') - f++; - if(*f == '~'){ - PNode* p; + for(b = f, i = 0; *b; b++) + if(*b == '~') + i++; + if(b!=f && b[-1] != '~') + i++; + bl = g_new(PBlock, i); + n->u.b.blocks = bl; + n->u.b.nblocks = i; + + for(b = f, i = 0; *b; i++){ + gint idx=0; + PNode* p = p_nil; + while(b[idx] && b[idx] != '~') + idx++; + bl[i].str = g_strndup(b, idx); + if(b[idx] == '~'){ p = va_arg(args, PNode*); BE_NODE(p); - if(p!=p_nil) - p_ref(p); - l = g_slist_prepend(l, p); - - f++; + p_ref(p); + idx++; } + bl[i].node = p; + b = &b[idx]; } - if(!l) - return p_str(f); - n = p_make(); - n->str = g_strdup(b); - n->children = g_slist_reverse(l); return n; } -PNode* p_lst(PNode* n, ...){ - va_list args; - GSList* l = NULL; - PNode* node; - g_assert(n); - va_start(args, n); - while(n){ - BE_NODE(n); - if(n!=p_nil){ - p_ref(n); - l = g_slist_prepend(l, n); - } - n = va_arg(args, PNode*); - } - node = p_make(); - node->children = g_slist_reverse(l); - return node; -} - -PNode* p_for(GSList* l, PNodeCreateFunc func, gpointer user_data){ - PNode* n = p_make(); - GSList* lst = NULL; - n->str = NULL; +PNode* p_for(GSList* lst, PNodeCreateFunc func, gpointer user_data){ + PNode* n = p_make(NODE_DATA); + GSList* l = lst; + gint i = g_slist_length(l); + n->u.b.nblocks = i; + n->u.b.blocks = g_new(PBlock, i); + i = 0; while(l){ PNode* p; - if(user_data==p_nil) - p=func(l->data); + if(user_data == p_nil) + p = func(l->data); else - p=func(l->data, user_data); + p = func(l->data, user_data); BE_NODE(p); - if(p!=p_nil){ - p_ref(p); - lst=g_slist_prepend(lst, p); - } - l=l->next; + p_ref(p); + n->u.b.blocks[i].str = NULL; + n->u.b.blocks[i++].node = p; + l = l->next; } - n->children=g_slist_reverse(lst); return n; } -typedef struct _PRNode{ - GQuark tag; - PNode* node; -} PRNode; - - -struct _PRoot{ - GList* nodes; -}; - +PNode* p_col(const gchar* tag, PNodeCreateFunc func){ + PNode* n = p_make(NODE_COLLECT); + n->u.c.func = func; + n->u.c.tag = g_quark_from_string(tag); + return n; +} PRoot* pr_new(void){ PRoot* pr = g_new(PRoot, 1); pr->nodes = NULL; + g_datalist_init(&pr->data); return pr; } @@ -237,27 +283,49 @@ void pr_add(PRoot* pr, const gchar* tag, PNode* node){ p_ref(node); } -void pr_write(PRoot* pr, FILE* stream, const gchar** tags, gint n){ - GList* l; - GQuark* quarks; - gint i; +void pr_put(PRoot* pr, const gchar* tag, gpointer datum){ + GHashTable* h = g_datalist_get_data(&pr->data, tag); + if(!h){ + h = g_hash_table_new(NULL, NULL); + g_datalist_set_data(&pr->data, tag, h); + } - quarks=g_new(GQuark, n); - for(i=0;inodes);l;l=l->prev){ PRNode* node = l->data; - for(i=0;itag==quarks[i]) - break; - if(i==n) - continue; - p_write(node->node, stream); + if(node->tag == q) + p_write(node->node, &w); } } +gchar* pr_to_str(PRoot* pr, const gchar* tag){ + FILE* f = tmpfile(); + glong len; + gchar* buf; + pr_write(pr, f, tag); + len = ftell(f); + rewind(f); + buf = g_new(gchar, len+1); + fread(buf, len, 1, f); + buf[len]='\0'; + fclose(f); + return buf; +} + + + void pr_free(PRoot* pr){ GList* l; for(l=pr->nodes;l;l = l->next){ diff --git a/tools/gcg/pnode.h b/tools/gcg/pnode.h index 973557e71a..a30ea9df24 100644 --- a/tools/gcg/pnode.h +++ b/tools/gcg/pnode.h @@ -13,19 +13,20 @@ typedef PNode* (*PNodeCreateFunc) (); void p_ref(PNode* node); void p_unref(PNode* node); -void p_write(PNode* node, FILE* f); PNode* p_str(const gchar* str); -PNode* p_qrk(const gchar* str); PNode* p_prf(const gchar* format, ...) G_GNUC_PRINTF(1, 2); PNode* p_fmt(const gchar* f, ...); PNode* p_lst(PNode* n, ...); PNode* p_for(GSList* l, PNodeCreateFunc func, gpointer user_data); -void p_traverse(PNode* node, PNodeTraverseFunc func, gpointer user_data); +PNode* p_col(const gchar* tag, PNodeCreateFunc func); PRoot* pr_new(void); void pr_add(PRoot* root, const gchar* tag, PNode* node); -void pr_write(PRoot* pr, FILE* stream, const gchar** tags, gint n); +void pr_put(PRoot* pr, const gchar* tag, gpointer datum); +void pr_write(PRoot* pr, FILE* stream, const gchar* tag); void pr_free(PRoot* root); +gchar* pr_to_str(PRoot* pr, const gchar* tags); + #endif