Initially committed to CVS.

This commit is contained in:
Lauri Alanko 1998-10-21 15:10:24 +00:00
parent 9005889d05
commit 91f868467c
19 changed files with 1681 additions and 0 deletions

3
tools/gcg/ChangeLog Normal file
View File

@ -0,0 +1,3 @@
1998-10-21 Lauri Alanko <la@iki.fi>
* Initially committed to CVS

38
tools/gcg/Makefile.am Normal file
View File

@ -0,0 +1,38 @@
noinst_PROGRAMS = gcg
CFLAGS=-I/usr/local/lib/glib/include -DYYDEBUG=1 -g -Wall -W -DCPP="$(CPP)"
INCLUDES = -DYYDEBUG=1 @GLIB_CFLAGS@
YFLAGS = -d -v 2>/dev/null
LIBS = @GLIB_LIBS@
lexer.c: $(srcdir)/lexer.l
@rm -f $@
$(LEX) $(LFLAGS) -t $< >$@
parser.c parser.h: $(srcdir)/parser.y
$(YACC) $(YFLAGS) $<
test -f y.tab.c && mv -f y.tab.c parser.c
test -f y.tab.h && mv -f y.tab.h parser.h
MOSTLYCLEANFILES = parser.output y.output
DISTCLEANFILES = parser.c parser.h lexer.c
EXTRA_DIST = parser.y lexer.l
BUILT_SOURCES = lexer.c parser.c parser.h
gcg_SOURCES = \
gcg.c \
parser.c \
lexer.c \
output.c \
output_basic.c \
db.c \
output_type.c \
output_enum.c \
output_flags.c \
output_object.c \
parser.h
gcg_DEPENDS = parser.h

6
tools/gcg/README Normal file
View File

@ -0,0 +1,6 @@
GCG - docs forthcoming (hopefully)
GCG is under development, it doesn't do much of anything sensible yet. What
little it does, you can test with:
gcg -t gimpimageT.h -f gimpimage.h -p gimpimageP.h -s gimpimage.c gimpimage.def

19
tools/gcg/autogen.sh Executable file
View File

@ -0,0 +1,19 @@
#!/bin/sh
if test -z "$*"; then
echo "I am going to run ./configure with no arguments - if you wish "
echo "to pass any to it, please specify them on the $0 command line."
fi
echo processing...
aclocal $ACLOCAL_FLAGS &&
automake --foreign &&
autoconf &&
./configure "$@"
if [ $? -eq 0 ];then
echo "Now type 'make' to compile GCG."
else
echo "Configuration error!"
fi

8
tools/gcg/configure.in Normal file
View File

@ -0,0 +1,8 @@
AC_INIT(gcg.c)
AM_INIT_AUTOMAKE(gcg, 0.1)
AC_PROG_CC
AC_PROG_CPP
AC_PROG_YACC
AM_PROG_LEX
AM_PATH_GLIB(1.0.0,,AC_ERROR(need at least Glib version 1.0))
AC_OUTPUT(Makefile)

25
tools/gcg/db.c Normal file
View File

@ -0,0 +1,25 @@
#include "gcg.h"
void put_decl(PrimType* t){
g_hash_table_insert(decl_hash, &t->name, t);
}
void put_def(Def* d){
g_hash_table_insert(def_hash, &d->type->name, d);
}
Def* get_def(Id module, Id type){
TypeName n;
n.module=module;
n.type=type;
return g_hash_table_lookup(def_hash, &n);
}
PrimType* get_decl(Id module, Id type){
TypeName n;
n.module=module;
n.type=type;
return g_hash_table_lookup(decl_hash, &n);
}

98
tools/gcg/gcg.c Normal file
View File

@ -0,0 +1,98 @@
#include "gcg.h"
#include "parser.h"
#include <stdio.h>
#include <glib.h>
#include <unistd.h>
#include "output.h"
GHashTable* decl_hash;
GHashTable* def_hash;
Id current_module;
Method* current_method;
ObjectDef* current_class;
Id current_header;
GSList* imports;
Id func_hdr_name;
Id type_hdr_name;
Id prot_hdr_name;
Id source_name;
Id impl_name;
void get_options(int argc, char* argv[]){
gint x=0;
do{
x=getopt(argc, argv, "f:t:p:s:i:");
switch(x){
case 'f':
func_hdr_name=optarg;
break;
case 't':
type_hdr_name=optarg;
break;
case 'p':
prot_hdr_name=optarg;
break;
case 's':
source_name=optarg;
break;
case 'i':
impl_name=optarg;
break;
case '?':
case ':':
g_error("Bad option %c!\n", x);
}
}while(x!=EOF);
}
guint type_name_hash(gconstpointer c){
const TypeName* t=c;
return g_str_hash(t->module) ^ g_str_hash(t->type);
}
gboolean type_name_cmp(gconstpointer a, gconstpointer b){
const TypeName *t1=a, *t2=b;
return (t1->type == t2->type) && (t1->module == t2->module);
}
void output_type(TypeName* t, Def* def, gpointer foo){
def->klass->output(def);
}
int main(int argc, char* argv[]){
extern int yydebug;
extern FILE* yyin;
/* target=stdout;*/
decl_hash=g_hash_table_new(type_name_hash, type_name_cmp);
def_hash=g_hash_table_new(type_name_hash, type_name_cmp);
yydebug=0;
get_options(argc, 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_decl(GET_ID("Gtk"), GET_ID("Type"));
g_assert(type_gtk_type->prim);
func_hdr=file_new(func_hdr_name);
type_hdr=file_new(type_hdr_name);
prot_hdr=file_new(prot_hdr_name);
source=file_new(source_name);
source_head=file_sub(source);
g_hash_table_foreach(def_hash, output_type, NULL);
file_flush(func_hdr);
file_flush(type_hdr);
file_flush(source_head);
/* file_flush(source);*/
file_flush(prot_hdr);
return 0;
}

167
tools/gcg/gcg.h Normal file
View File

@ -0,0 +1,167 @@
#ifndef __GCG_H__
#define __GCG_H__
#include <glib.h>
typedef const gchar* Id;
#define GET_ID(x) (g_quark_to_string(g_quark_from_string(x)))
typedef const gchar* Header;
typedef struct _Member Member;
typedef struct _TypeName TypeName;
typedef struct _PrimType PrimType;
typedef struct _Type Type;
typedef struct _ObjectDef ObjectDef;
typedef struct _Def Def;
typedef struct _EnumDef EnumDef;
typedef struct _FlagsDef FlagsDef;
typedef struct _DataMember DataMember;
typedef struct _Method Method;
typedef struct _MemberClass MemberClass;
typedef struct _DefClass DefClass;
typedef struct _Param Param;
struct _TypeName {
Id module;
Id type;
};
typedef enum {
TYPE_CLASS,
TYPE_OPAQUE,
TYPE_TRANSPARENT
} TypeKind;
struct _PrimType {
TypeName name;
TypeKind kind;
Id decl_header;
Id def_header;
};
struct _Type {
gboolean is_const; /* concerning the _ultimate dereferenced_ object */
gint indirection; /* num of pointers to type */
gboolean notnull; /* concerning the _immediate pointer_ */
PrimType* prim;
};
struct _DefClass {
void (*output)(Def*);
};
struct _Def {
DefClass *klass;
PrimType *type;
GString* doc;
};
#define DEF(x) ((Def*)(x))
extern DefClass enum_class;
struct _EnumDef {
Def def;
GSList* alternatives; /* list of Id */
};
extern DefClass flags_class;
struct _FlagsDef {
Def def;
GSList* flags; /* list of Id */
};
extern DefClass object_class;
struct _ObjectDef {
Def def;
PrimType* parent;
GSList* members;
};
typedef enum {
KIND_DIRECT,
KIND_ABSTRACT,
KIND_STATIC
} MemberKind;
typedef enum {
METH_PUBLIC,
METH_PROTECTED
} MethodProtection;
typedef enum {
DATA_READWRITE,
DATA_READONLY,
DATA_PROTECTED
} DataProtection;
typedef enum _EmitDef{
EMIT_NONE,
EMIT_PRE,
EMIT_POST
} EmitDef;
typedef enum _MemberType{
MEMBER_DATA,
MEMBER_METHOD,
MEMBER_SIGNAL
} MemberType;
struct _Member{
MemberType membertype;
MemberKind kind;
ObjectDef* my_class;
Id name;
GString* doc;
};
#define MEMBER(x) ((Member*)(x))
struct _DataMember {
Member member;
DataProtection prot;
Type type;
};
struct _Method {
Member member;
MethodProtection prot;
GSList* params; /* list of Param* */
gboolean self_const;
Type ret_type;
};
struct _Param {
Id name;
Method* method;
GString* doc;
Type type;
};
void put_decl(PrimType* t);
void put_def(Def* d);
PrimType* get_decl(Id module, Id type);
Def* get_def(Id module, Id type);
extern Type* type_gtk_type;
extern Id current_header;
extern Id current_module;
extern ObjectDef* current_class;
extern GSList* imports;
extern Method* current_method;
extern GHashTable* def_hash;
extern GHashTable* decl_hash;
#endif

33
tools/gcg/gimpimage.def Normal file
View File

@ -0,0 +1,33 @@
module g {
header <glib.h> {
type int;
};
};
module Gtk {
header <gtk/gtktypeutils.h> {
type Type;
};
};
module Gimp{
header <gimp/gimpobject.h> {
class Object;
};
header <gimp/gimpimage.h> {
class Image;
type ImageType;
type Thingy;
};
enum ImageType{
rgb, gray, indexed, rgb-alpha };
flags Thingy{
foo, bar, baz, quux
};
class Image : Gimp.Object{
g.int x;
read-only g.int y;
};
};

73
tools/gcg/lexer.l Normal file
View File

@ -0,0 +1,73 @@
%option noyywrap
%{
#include "gcg.h"
#include "parser.h"
%}
ident [A-Za-z][A-Za-z0-9-]*
header <[[:alnum:]/.]+>
ws [ \n\t\r]
comment \/\/[^\n]*\n
string \"(([^\"]*)|\\\"|\\\\)*\"
%%
class return T_CLASS;
public return T_PUBLIC;
static return T_STATIC;
protected return T_PROTECTED;
pre-emit return T_PRE_EMIT;
post-emit return T_POST_EMIT;
read-only return T_READ_ONLY;
read-write return T_READ_WRITE;
private return T_PRIVATE;
const return T_CONST;
abstract return T_ABSTRACT;
direct return T_DIRECT;
type return T_TYPE;
attribute return T_ATTRIBUTE;
module return T_MODULE;
enum return T_ENUM;
flags return T_FLAGS;
import return T_IMPORT;
header return T_HEADER;
opaque return T_OPAQUE;
void return T_VOID;
{comment} {
}
{ws} {
}
{ident} {
yylval.id=g_quark_to_string(g_quark_from_string(yytext));
return T_IDENT;
}
{header} {
yylval.id=g_quark_to_string(g_quark_from_string(yytext));
return T_HEADERNAME;
}
{string} {
yylval.str=g_string_new(yytext);
return T_STRING;
}
\. return T_SCOPE;
\* return T_POINTER;
\& return T_NOTNULLPTR;
\; return T_END;
\{ return T_OPEN_B;
\} return T_CLOSE_B;
\( return T_OPEN_P;
\) return T_CLOSE_P;
\, return T_COMMA;
\: return T_INHERITANCE;
. return yytext[0];
%%

62
tools/gcg/main.c Normal file
View File

@ -0,0 +1,62 @@
#include "classc.h"
#include "parser.h"
#include <stdio.h>
#include <glib.h>
#include <unistd.h>
#include "output.h"
GHashTable* decl_hash;
GHashTable* def_hash;
Id current_module;
Method* current_method;
ObjectDef* current_class;
Id current_header;
GSList* imports;
guint type_name_hash(gconstpointer c){
const TypeName* t=c;
return g_str_hash(t->module) ^ g_str_hash(t->type);
}
gboolean type_name_cmp(gconstpointer a, gconstpointer b){
const TypeName *t1=a, *t2=b;
return (t1->type == t2->type) && (t1->module == t2->module);
}
void output_type(TypeName* t, Def* def, gpointer foo){
def->klass->output(def);
}
int main(int argc, char* argv[]){
extern int yydebug;
extern FILE* yyin;
/* target=stdout;*/
decl_hash=g_hash_table_new(type_name_hash, type_name_cmp);
def_hash=g_hash_table_new(type_name_hash, type_name_cmp);
yydebug=0;
yyin=fopen(argv[1], "r");
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_decl(GET_ID("Gtk"), GET_ID("Type"));
g_assert(type_gtk_type->prim);
func_hdr=file_new("gen_funcs.h");
type_hdr=file_new("gen_types.h");
prot_hdr=file_new("gen_prots.h");
source=file_new("gen_source.c");
source_head=file_sub(source);
g_hash_table_foreach(def_hash, output_type, NULL);
file_flush(func_hdr);
file_flush(type_hdr);
file_flush(source_head);
/* file_flush(source);*/
file_flush(prot_hdr);
return 0;
}

142
tools/gcg/output.c Normal file
View File

@ -0,0 +1,142 @@
#include <stdio.h>
#include "output.h"
#include <stdarg.h>
void pr_param(File* s, Param* p, PBool first){
pr(s, "%?s%1 %s",
!first, ", ",
pr_type, p->type,
p->name);
}
void pr_params(File* s, GSList* args){
pr(s, "%?s%?2%3",
!args, "void",
!!args, pr_param, args?args->data:NULL, ptrue,
pr_list_foreach, (args?args->next:NULL), pr_param, pfalse);
}
void pr_primtype(File* s, PrimType* t){
pr(s, "%s%s",
t->name.module,
t->name.type);
}
void pr_type(File* s, Type* t){
gint i=t->indirection;
if(t->prim){
pr(s, "%?s%1",
t->is_const, "const ",
pr_primtype, t->prim);
while(i--)
pr_c(s, '*');
if(t->indirection)
file_add_dep(s, t->prim->decl_header);
else
file_add_dep(s, t->prim->def_header);
}else
pr(s, "void");
}
void pr_self_type(File* s, ObjectDef* o, PBool const_self){
pr(s, "%?s%2*",
!!const_self, "const ",
pr_primtype, DEF(o)->type);
}
void pr_varname(File* s, PrimType* t, Id name){
pr(s, "%1_%1_%1",
pr_low, t->name.module,
pr_low, t->name.type,
pr_low, name);
}
void pr_internal_varname(File* s, PrimType* t, Id name){
pr(s, "_%2",
pr_varname, t, name);
}
void pr_prototype(File* s, PrimType* type, Id funcname,
GSList* params, Type* rettype, gboolean internal){
pr(s, "%1 %2 (%1)",
pr_type, rettype,
(internal?pr_internal_varname:pr_varname), type, funcname,
pr_params, params);
}
void pr_type_guard(File* s, Param* p){
Type* t=&p->type;
if(t->indirection==1 && t->prim->kind == TYPE_CLASS)
/* A direct object pointer is checked for its type */
pr(s, "\tg_assert(%?2%3(%s));",
!t->notnull, pr, "!%s || ", p->name,
pr_macro_name, t->prim->name, "IS", NULL,
p->name);
else if(t->indirection && t->notnull)
/* Other pointers are just possibly checked for nullness */
pr(s, "\tg_assert(%s);",
p->name);
/* todo (low priority): range checks for enums */
}
void output_func(PrimType* type, Id funcname, GSList* params, Type* rettype,
File* hdr, ObjectDef* self, gboolean self_const,
gboolean internal, const gchar* body, ...){
GSList l;
Param p;
va_list args;
if(self){
p.type.prim=DEF(self)->type;
p.type.indirection=1;
p.type.is_const=self_const;
p.type.notnull=TRUE;
p.name="self";
l.data=&p;
l.next=params;
params=&l;
}
va_start(args, body);
pr((hdr?hdr:source_head), "%?s%5;\n",
!hdr, "static ",
pr_prototype, type, funcname, params, rettype, internal);
pr(source,
"%?s%5{\n"
"%3"
"%v"
"}\n",
!hdr, "static ",
pr_prototype, type, funcname, params, rettype, internal,
pr_list_foreach, params, pr_type_guard, no_data,
body, args);
}
void pr_macro_name(File* s, PrimType* t, Id mid, Id post){
pr(s,
"%1%?s%?1_%1%?s%?1",
pr_up, t->name.module,
!!mid, "_",
!!mid, pr_up, mid,
pr_up, t->name.type,
!!post, "_",
!!post, pr_up, post);
}
void output_var(Def* d, Type* t, Id varname, File* hdr, gboolean internal){
if(hdr)
pr(hdr,
"extern %1 %2;\n",
pr_type, t,
(internal?pr_internal_varname:pr_varname), &d->type->name,
varname);
pr(source_head,
"%?s%1 %2;\n",
!hdr, "static ",
pr_type, t,
(internal?pr_internal_varname:pr_varname), &d->type->name,
varname);
}

64
tools/gcg/output.h Normal file
View File

@ -0,0 +1,64 @@
#ifndef __OUTPUT_H__
#define __OUTPUT_H__
#include "gcg.h"
#include <stdio.h>
typedef gconstpointer PBool;
extern const PBool ptrue;
extern const PBool pfalse;
typedef enum{
VAR_STATIC,
VAR_PUBLIC,
VAR_PROTECTED
} VarProt;
typedef struct _File File;
File* file_new(const gchar* filename);
void file_flush(File* f);
void file_add_dep(File* f, Id header);
extern File* type_hdr;
extern File* func_hdr;
extern File* prot_hdr;
extern File* pub_import_hdr;
extern File* prot_import_hdr;
extern File* source;
extern File* source_head; /* "private header", so to say */
void pr(File* s, const gchar* f, ...);
void prv(File* s, const gchar* f, va_list args);
void pr_nil(File* s, ...);
void pr_c(File* s, gchar c);
void pr_low(File* s, const gchar* str);
void pr_up(File* s, const gchar* str);
extern const gconstpointer no_data;
void pr_list_foreach(File* s, GSList* l, void (*f)(), gpointer arg);
void pr_params(File* s, GSList* args);
void pr_primtype(File* s, PrimType* t);
void pr_type(File* s, Type* t);
void pr_self_type(File* s, ObjectDef* c, PBool const_self);
void pr_varname(File* s, PrimType* t, Id name);
void pr_internal_varname(File* s, PrimType* t, Id name);
void pr_object_member(File* s, Member* m);
void pr_object_body(File* s, ObjectDef* c);
void pr_object_decl(File* s, ObjectDef* c);
void pr_class_member(File* s, Member* m);
void pr_class_body(File* s, ObjectDef* c);
void pr_class_decl(File* s, ObjectDef* c);
void pr_prototype(File* s, PrimType* type, Id funcname,
GSList* params, Type* rettype, gboolean internal);
void pr_func(ObjectDef* self, Id funcname, GSList* params, Type* rettype,
VarProt prot, gboolean with_self, const gchar* body, ...);
void pr_macro_name(File* s, PrimType* t, Id mid, Id post);
void pr_class_macros(File* s, ObjectDef* c );
void pr_get_type(File* s, ObjectDef* c);
void pr_gtype(File* s, Type* t);
void pr_guard_name(File* s, const gchar* c);
void pr_guard_start(File* s, const gchar *c);
void pr_guard_end(File* s, const gchar *c);
#endif

256
tools/gcg/output_basic.c Normal file
View File

@ -0,0 +1,256 @@
#include <stdarg.h>
#include <stdio.h>
#include <glib.h>
#include <ctype.h>
#include "output.h"
const PBool ptrue = &ptrue;
const PBool pfalse = NULL;
File* type_hdr;
File* func_hdr;
File* prot_hdr;
File* pub_import_hdr;
File* prot_import_hdr;
File* source;
File* source_head; /* inlined to the source */
struct _File{
FILE* stream;
const gchar* filename;
File* parent;
GHashTable* deps;
};
void write_guard_name(FILE* s, const gchar* c){
gboolean enc=FALSE;
fputs("_g_", s);
while(*c){
if(isalnum(*c))
fputc(*c, s);
else
fputc('_', s);
c++;
}
fputc('_', s);
}
void write_guard_start(FILE* s, const gchar *c){
fputs("#ifndef ", s);
write_guard_name(s, c);
fputs("\n#define ", s);
write_guard_name(s, c);
fputs("\n", s);
}
void write_guard_end(FILE* s, const gchar *c){
fputs("#endif /* ", s);
write_guard_name(s, c);
fputs(" */\n", s);
}
File* file_new(const gchar* filename){
File* f=g_new(File, 1);
f->stream=tmpfile();
f->filename=filename;
f->deps=g_hash_table_new(g_str_hash, g_str_equal);
f->parent=NULL;
return f;
}
File* file_sub(File* parent){
File* f=g_new(File, 1);
f->stream=tmpfile();
f->filename=NULL;
f->deps=NULL;
f->parent=parent;
return f;
}
void file_add_dep(File* f, Id header){
while(f->parent)
f=f->parent;
g_hash_table_insert(f->deps, header, NULL);
}
void write_dep(gpointer key, gpointer value, gpointer user_data){
Id i=key;
FILE* stream=user_data;
fprintf(stream, "#include %s\n", i);
}
void file_flush(File* f){
File* root;
File* old;
static const gint bufsize=1024;
FILE* real;
guint8 buf[bufsize];
size_t i;
for(root=f;root->parent;root=root->parent);
real=fopen(root->filename, "w+");
g_assert(real);
write_guard_start(real, root->filename); /* more scoping needed */
g_hash_table_foreach(root->deps, write_dep, real);
fflush(root->stream);
old=NULL;
while(f){
g_free(old);
rewind(f->stream);
i=0;
do{
i=fread(buf, 1, bufsize, f->stream);
fwrite(buf, 1, i, real);
}while(i==bufsize);
fclose(f->stream);
old=f;
f=f->parent;
}
write_guard_end(real, root->filename);
fclose(real);
g_hash_table_destroy(root->deps);
g_free(root);
}
typedef void (*Func)();
const Func nilf = 0;
static void call_func(Func fun, File* s, gpointer* x, gint nargs){
switch(nargs){
case 0:
fun(s);
break;
case 1:
fun(s, x[0]);
break;
case 2:
fun(s, x[0], x[1]);
break;
case 3:
fun(s, x[0], x[1], x[2]);
break;
case 4:
fun(s, x[0], x[1], x[2], x[3]);
break;
case 5:
fun(s, x[0], x[1], x[2], x[3], x[4]);
break;
case 6:
fun(s, x[0], x[1], x[2], x[3], x[4], x[5]);
break;
case 7:
fun(s, x[0], x[1], x[2], x[3], x[4], x[5], x[6]);
break;
case 8:
fun(s, x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7]);
break;
case 9:
fun(s, x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8]);
break;
}
}
void prv(File* s, const gchar* f, va_list args){
gint i=0;
if(!s)
return;
while(*f){
while(f[i] && f[i]!='%')
i++;
fwrite(f, i, 1, s->stream);
f+=i;
i=0;
if(f[0]=='%'){
char c=f[1];
gboolean doit=TRUE;
f+=2;
if(c=='%')
fputc('%', s->stream);
else if(c=='?'){
doit=va_arg(args, gboolean);
c=*f++;
}
if(c=='s'){
const gchar* str=va_arg(args, const gchar*);
if(doit)
fputs(str, s->stream);
} else if(c=='d'){
gint n;
n=va_arg(args, gint);
fprintf(s->stream, "%d", n);
} else if(c=='v'){
const gchar* nextformat;
va_list nextargs;
nextformat=va_arg(args, const gchar*);
nextargs=va_arg(args, va_list);
if(doit)
prv(s, nextformat, nextargs);
}else if(c>='0' && c<='9'){
Func fun;
gint n;
gpointer x[8];
fun=va_arg(args, Func);
for(n=0;n<c-'0';n++)
x[n]=va_arg(args, gpointer);
if(doit)
call_func(fun, s, x, c-'0');
} else g_error("Bad format\n");
}
}
}
void pr(File* s, const gchar* format, ...){
va_list args;
va_start(args, format);
prv(s, format, args);
va_end(args);
}
void pr_f(File* s, const gchar* format, ...){
va_list args;
va_start(args, format);
vfprintf(s->stream, format, args);
va_end(args);
}
void pr_nil(File* s, ...){
}
void pr_c(File* s, gchar c){
if(s)
fputc(c, s->stream);
}
void pr_low(File* s, const gchar* str){
gchar x;
while(*str){
x=*str++;
pr_c(s, (x=='-')?'_':tolower(x));
}
}
void pr_up(File* s, const gchar* str){
gchar x;
while(*str){
x=*str++;
pr_c(s, (x=='-')?'_':toupper(x));
}
}
const gconstpointer no_data = &no_data;
/* This depends on a func pointer being about the same as a gpointer */
void pr_list_foreach(File* s, GSList* l, void (*f)(), gpointer arg){
while(l){
if(arg==no_data)
f(s, l->data);
else
f(s, l->data, arg);
l=l->next;
}
}

55
tools/gcg/output_enum.c Normal file
View File

@ -0,0 +1,55 @@
#include "output.h"
void pr_enum_member(File* s, Id id, PrimType* t){
pr(s,
"\t%3,\n",
pr_macro_name, t, NULL, id);
}
void pr_enum_decl(File* s, EnumDef* e){
pr(s,
"typedef enum {\n"
"%3"
"} %1;\n",
pr_list_foreach, e->alternatives, pr_enum_member, DEF(e)->type,
pr_primtype, DEF(e)->type);
}
void pr_enum_value(File* s, Id i, PrimType* t){
pr(s,
"\t\t{%3,\n"
"\t\t\"%3\",\n"
"\t\t\"%s\"},\n",
pr_macro_name, t, NULL, i,
pr_macro_name, t, NULL, i,
i);
}
void output_enum_type_init(EnumDef* e){
PrimType* t=DEF(e)->type;
output_func(t, "init_type", NULL, type_gtk_type, type_hdr, NULL,
FALSE, TRUE,
"\tstatic GtkEnumValue values[%d] = {\n"
"%3"
"\t\t{0, NULL, NULL}\n"
"\t};\n"
"\t%2 = gtk_type_register_enum (\"%1\", values);\n"
"\treturn %2;\n",
g_slist_length(e->alternatives)+1,
pr_list_foreach, e->alternatives, pr_enum_value, t,
pr_internal_varname, t, "type",
pr_primtype, t,
pr_internal_varname, t, "type");
}
void output_enum(EnumDef* e){
output_def(DEF(e));
output_enum_type_init(e);
pr_enum_decl(type_hdr, e);
}
DefClass enum_class={
output_enum
};

66
tools/gcg/output_flags.c Normal file
View File

@ -0,0 +1,66 @@
#include "output.h"
typedef struct {
gint i;
PrimType* t;
}FlagData;
void pr_flags_member(File* s, Id id, FlagData* d){
pr(s,
"\t%3 = 1 << %d,\n",
pr_macro_name, d->t, NULL, id,
d->i);
d->i++;
}
void pr_flags_decl(File* s, FlagsDef* e){
FlagData d={
0,
DEF(e)->type
};
pr(s,
"typedef enum {\n"
"%3"
"} %1;\n",
pr_list_foreach, e->flags, pr_flags_member, &d,
pr_primtype, d.t);
}
void pr_flags_value(File* s, Id i, PrimType* t){
pr(s,
"\t\t{%3,\n"
"\t\t\"%3\",\n"
"\t\t\"%s\"},\n",
pr_macro_name, t, NULL, i,
pr_macro_name, t, NULL, i,
i);
}
void output_flags_type_init(FlagsDef* e){
PrimType* t=DEF(e)->type;
output_func(t, "init_type", NULL, type_gtk_type, type_hdr, NULL,
FALSE, TRUE,
"\tstatic GtkFlagValue values[%d] = {\n"
"%3"
"\t\t{0, NULL, NULL}\n"
"\t};\n"
"\t%2 = gtk_type_register_flags (\"%1\", values);\n"
"\treturn %2;\n",
g_slist_length(e->flags)+1,
pr_list_foreach, e->flags, pr_flags_value, t,
pr_internal_varname, t, "type",
pr_primtype, t,
pr_internal_varname, t, "type");
}
void output_flags(FlagsDef* e){
output_def(DEF(e));
pr_flags_decl(type_hdr, e);
output_flags_type_init(e);
}
DefClass flags_class={
output_flags
};
Type* type_gtk_type;

190
tools/gcg/output_object.c Normal file
View File

@ -0,0 +1,190 @@
#include "output.h"
void pr_object_member(File* s, Member* m){
DataMember* d;
if(m->membertype != MEMBER_DATA
|| m->kind != KIND_DIRECT)
return;
d=(DataMember*)m;
pr(s, "\t%1 %1;\n",
pr_type, &d->type,
pr_low, m->name);
}
void pr_object_body(File* s, ObjectDef* o){
GSList* l;
pr(s, "struct _%1 {\n"
"\t%1 parent;\n"
"%3"
"};\n",
pr_primtype, DEF(o)->type,
pr_primtype, o->parent,
pr_list_foreach, o->members, pr_object_member, no_data);
}
void pr_object_decl(File* s, ObjectDef* o){
PrimType* n=DEF(o)->type;
pr(s,
"#ifdef STRICT_OBJECT_TYPES\n"
"typedef struct _%1 %1;\n"
"#else\n"
"typedef struct _GenericObject %1;\n"
"#endif\n",
pr_primtype, n,
pr_primtype, n,
pr_primtype, n);
}
void pr_class_member(File* s, Member* m){
#if 0
if(m->kind!=KIND_ABSTRACT)
return;
pr(s, "\t%1 %1%5;\n",
pr_type, m->type,
(m->method?pr_nil:pr), m->name
(m->method?pr:pr_nil), "(*%s) (%2)",
m->name,
pr_params, m->params, ptrue);
#endif
}
void pr_class_name(File* s, PrimType* o){
pr(s, "%1Class",
pr_primtype, o);
}
void pr_impl_name(File* s, ObjectDef* o){
pr(s, "%1Impl",
pr_type, DEF(o)->type);
}
void pr_class_body(File* s, ObjectDef* o){
pr(s,
"struct _%1 {\n"
"\t%1 parent_class;\n"
"%3"
"};\n",
pr_class_name, DEF(o)->type,
pr_class_name, o->parent,
pr_list_foreach, o->members, pr_class_member, no_data);
}
void pr_class_decl(File* s, ObjectDef* o){
pr(s,
"typedef struct _%1 %1;\n",
pr_class_name, DEF(o)->type,
pr_class_name, DEF(o)->type);
}
void pr_class_cast(File* s, ObjectDef* t, const gchar* format, ...){
va_list args;
va_start (args, format);
pr(s, "%3 (%2)",
pr_macro_name, DEF(t)->type, NULL, "CLASS_CAST",
prv, format, args);
}
void pr_abstract_member(File* s, Id varname, ObjectDef* klass, Id membername){
pr(s,
"(%3->%s)",
pr_class_cast, klass, "GTK_OBJECT(%s)->klass", varname,
membername);
}
void output_method_funcs(Method* m){
PrimType* t=DEF(MEMBER(m)->my_class)->type;
Id name=MEMBER(m)->name;
output_func
(t,
name,
m->params,
&m->ret_type,
m->prot==METH_PUBLIC?func_hdr:prot_hdr,
MEMBER(m)->my_class,
m->self_const,
FALSE,
"\t%?s%?5%%%%",
!!m->ret_type.prim, "return ",
MEMBER(m)->kind==KIND_ABSTRACT,
pr, "%2%2", pr_abstract_member, "self", t, name
);
}
/*
void pr_accessor_def(...){
Param p;
GSList l;
l.data=&p;
mk_self_param(
pr_func(m->klass, m->name, ,
"\treturn self->%s;\n");
*/
void pr_class_macros(File* s, ObjectDef* o ){
PrimType* t=DEF(o)->type;
pr(s, "#define %3(o) GTK_CHECK_CAST(o, %3, %1)\n",
pr_macro_name, t, NULL, NULL,
pr_macro_name, t, "TYPE", NULL,
pr_primtype, t);
pr(s, "#define %3(o) GTK_CHECK_TYPE(o, %3)\n",
pr_macro_name, t, "IS", NULL,
pr_macro_name, t, "TYPE", NULL);
}
void output_object_type_init(ObjectDef* o){
PrimType* t=DEF(o)->type;
output_func(t, "init_type", NULL, type_gtk_type, type_hdr, NULL,
FALSE, TRUE,
"\tstatic GtkTypeInfo info = {\n"
"\t\t\"%1\",\n"
"\t\tsizeof (%1),\n"
"\t\tsizeof (%1),\n"
"\t\t(GtkClassInitFunc) %2,\n"
"\t\t(GtkObjectInitFunc) %2,\n"
"\t\tNULL,\n"
"\t\tNULL,\n"
"\t\tNULL,\n"
"\t};\n"
"\t%2 = gtk_type_unique (%3, &info);\n"
"\treturn %2;\n",
pr_primtype, t,
pr_primtype, t,
pr_class_name, o,
pr_varname, t, "class_init",
pr_varname, t, "init",
pr_internal_varname, t, "type",
pr_macro_name, o->parent, "TYPE", NULL,
pr_internal_varname, t, "type");
}
void pr_gtype(File* s, Type* t){
if((t->indirection==0 && t->prim->kind==TYPE_TRANSPARENT)
|| (t->indirection==1 && t->prim->kind==TYPE_CLASS))
pr_macro_name(s, t->prim, "TYPE", NULL);
else if(t->indirection)
pr(s, "GTK_TYPE_POINTER");
else
g_error("Illegal non-pointer type %s%s\n",
t->prim->name.module,
t->prim->name.type);
}
void output_object(ObjectDef* o){
output_def(DEF(o));
output_object_type_init(o);
pr_class_body(prot_hdr, o);
pr_class_decl(prot_hdr, o);
pr_object_decl(type_hdr, o);
pr_object_body(prot_hdr, o);
}
DefClass object_class={
output_object
};

14
tools/gcg/output_type.c Normal file
View File

@ -0,0 +1,14 @@
#include "output.h"
void output_def(Def* d){
TypeName* t=&d->type->name;
/* GTK_TYPE_FOO macro */
pr(type_hdr,
"#define %3 \\\n"
" (%2 ? %2 : %2())\n",
pr_macro_name, t, "TYPE", NULL,
pr_internal_varname, t, "type",
pr_internal_varname, t, "type",
pr_internal_varname, t, "init_type");
output_var(d, type_gtk_type, "type", type_hdr, TRUE);
}

362
tools/gcg/parser.y Normal file
View File

@ -0,0 +1,362 @@
%{
#include "gcg.h"
#define YYDEBUG 1
%}
%union {
GSList* list;
Id id;
GString* str;
TypeName typename;
PrimType* primtype;
MethodProtection methprot;
DataProtection dataprot;
MemberKind kind;
Def* def;
ObjectDef* class_def;
Member* member;
Param* param;
EmitDef emit_def;
gboolean bool;
Type type;
};
%token T_MODULE
%token T_ENUM
%token T_FLAGS
%token T_READ_WRITE
%token T_READ_ONLY
%token T_PRIVATE
%token T_PROTECTED
%token T_PUBLIC
%token T_CLASS
%token T_PRE_EMIT
%token T_POST_EMIT
%token T_SCOPE
%token T_ABSTRACT
%token T_EMPTY
%token T_DIRECT
%token T_STATIC
%token T_CONST
%token T_TYPE
%token T_END
%token T_OPEN_B
%token T_POINTER
%token T_NOTNULLPTR
%token T_CLOSE_B
%token T_INHERITANCE
%token T_ATTRIBUTE
%token T_HEADER
%token T_OPEN_P
%token T_HEADER
%token T_CLOSE_P
%token T_COMMA
%token T_IMPORT
%token T_OPAQUE
%token T_VOID
%token<id> T_IDENT
%token<id> T_HEADERNAME
%token<str> T_STRING
%type<type> type
%type<type> typeorvoid
%type<type> semitype
%type<typename> typename
%type<primtype> primtype
%type<list> paramlist
%type<list> idlist
%type<kind> kinddef
%type<methprot> methprot
%type<dataprot> dataprot
%type<list> classbody
%type<def> flagsdef
%type<def> enumdef
%type<def> classdef
%type<def> def
%type<primtype> object_type
%type<list> paramtail
%type<param> param
%type<str> docstring
%type<member> member_def
%type<member> data_member_def
%type<member> method_def
%type<emit_def> emitdef
%type<bool> const_def;
%% /* Grammar rules and actions follow */
start_symbol: deffile ;
deffile: /* empty */ | deffile import | deffile modulescope;
import: T_IMPORT T_IDENT T_END {
imports=g_slist_prepend(imports, (gpointer)($2));
}
modulescope: T_MODULE T_IDENT T_OPEN_B {
current_module=$2;
} modulebody T_CLOSE_B {
current_module=NULL;
} T_END;
modulebody: /* empty */ | modulebody headerdef | modulebody def {
put_def ($2);
};
headerdef: T_HEADER T_HEADERNAME T_OPEN_B {
current_header=$2;
} decllist T_CLOSE_B {
current_header=NULL;
} T_END;
decllist: /* empty */ | decllist decl;
decl: simpledecl | classdecl | opaquedecl | protclassdecl;
simpledecl: T_TYPE typename T_END {
PrimType* t=g_new(PrimType, 1);
t->name = $2;
t->kind=TYPE_TRANSPARENT;
t->decl_header = t->def_header = current_header;
put_decl(t);
};
protclassdecl: T_PROTECTED T_CLASS typename T_END {
PrimType* t;
t=get_decl($3.module, $3.type);
if(!t){
t=g_new(PrimType, 1);
t->name=$3;
t->kind=TYPE_CLASS;
t->decl_header=NULL;
}
g_assert(t->kind==TYPE_CLASS);
t->def_header=current_header;
put_decl(t);
}
classdecl: T_CLASS typename T_END {
PrimType* t;
t=get_decl($2.module, $2.type);
if(!t){
t=g_new(PrimType, 1);
t->name=$2;
t->kind=TYPE_CLASS;
t->def_header=NULL;
}
g_assert(t->kind==TYPE_CLASS);
t->decl_header=current_header;
put_decl(t);
}
opaquedecl: T_OPAQUE typename T_END {
PrimType* t=g_new(PrimType, 1);
t->name = $2;
t->kind=TYPE_OPAQUE;
t->decl_header = NULL;
t->def_header = current_header;
g_assert(!get_decl($2.module, $2.type));
put_decl(t);
};
semitype: const_def primtype {
$$.is_const = $1;
$$.indirection = 0;
$$.notnull = FALSE;
$$.prim = $2;
} | semitype T_POINTER {
$$ = $1;
$$.indirection++;
};
type: semitype | semitype T_NOTNULLPTR {
$$ = $1;
$$.indirection++;
$$.notnull = TRUE;
}
typeorvoid: type | T_VOID {
$$.prim = NULL;
$$.indirection = 0;
$$.is_const = FALSE;
$$.notnull = FALSE;
}
primtype: typename {
$$=get_decl($1.module, $1.type);
g_assert($$);
};
typename: T_IDENT T_SCOPE T_IDENT {
$$.module=$1;
$$.type=$3;
} | T_IDENT {
g_assert(current_module);
$$.module=current_module;
$$.type=$1;
};
object_type: primtype {
$$=$1;
g_assert($$->kind==TYPE_CLASS);
};
paramlist: /* empty */ {
$$ = NULL;
} | param paramtail {
$$ = g_slist_prepend($2, $1);
};
paramtail: /* empty */ {
$$ = NULL;
} | T_COMMA param paramtail {
$$ = g_slist_prepend($3, $2);
};
param: type T_IDENT docstring {
$$=g_new(Param, 1);
$$->method=current_method;
$$->doc=$3;
$$->name=$2;
$$->type=$1;
};
kinddef: T_ABSTRACT {
$$ = KIND_ABSTRACT;
} | T_DIRECT {
$$ = KIND_DIRECT;
} | /* empty */ {
$$ = KIND_DIRECT;
} | T_STATIC {
$$ = KIND_STATIC;
};
methprot: T_PROTECTED{
$$ = METH_PROTECTED;
} | T_PUBLIC {
$$ = METH_PUBLIC;
};
dataprot: /* empty */ {
$$ = DATA_PROTECTED;
} | T_READ_ONLY {
$$ = DATA_READONLY;
} | T_READ_WRITE {
$$ = DATA_READWRITE;
};
emitdef: /* empty */ {
$$ = EMIT_NONE;
} | T_PRE_EMIT {
$$ = EMIT_PRE;
} | T_POST_EMIT {
$$ = EMIT_POST;
};
docstring: T_STRING {
$$ = $1;
} | /* empty */ {
$$ = NULL;
};
idlist: T_IDENT {
$$ = g_slist_prepend(NULL, (gpointer)($1));
} | idlist T_COMMA T_IDENT {
$$ = g_slist_append($1, (gpointer)($3));
};
def: classdef | enumdef | flagsdef;
enumdef: T_ENUM primtype T_OPEN_B idlist T_CLOSE_B docstring T_END {
EnumDef* d=g_new(EnumDef, 1);
g_assert($2->kind==TYPE_TRANSPARENT);
d->alternatives = $4;
$$=DEF(d);
$$->klass=&enum_class;
$$->type=$2;
$$->doc=$6;
};
flagsdef: T_FLAGS primtype T_OPEN_B idlist T_CLOSE_B docstring T_END {
FlagsDef* d=g_new(FlagsDef, 1);
g_assert($2->kind==TYPE_TRANSPARENT);
d->flags = $4;
$$=DEF(d);
$$->klass=&flags_class;
$$->type=$2;
$$->doc=$6;
};
classdef: T_CLASS object_type T_INHERITANCE object_type docstring T_OPEN_B {
current_class=g_new(ObjectDef, 1);
} classbody T_CLOSE_B T_END {
current_class->parent = $4;
current_class->members = $8;
$$=DEF(current_class);
current_class=NULL;
$$->klass=&object_class;
$$->type = $2;
$$->doc = $5;
};
member_def: data_member_def | method_def;
data_member_def: dataprot kinddef type T_IDENT emitdef docstring T_END {
DataMember* m = g_new(DataMember, 1);
m->prot = $1;
m->type = $3;
$$ = MEMBER(m);
$$->membertype = MEMBER_DATA;
$$->kind = $2;
$$->name = $4;
/* $$->emit = $5; */
$$->doc = $6;
};
method_def: methprot kinddef typeorvoid T_IDENT T_OPEN_P {
current_method = g_new(Method, 1);
} paramlist T_CLOSE_P const_def emitdef docstring T_END {
current_method = NULL;
current_method->prot = $1;
current_method->ret_type = $3;
current_method->self_const = $9;
current_method->params = $7;
$$=MEMBER(current_method);
current_method=NULL;
$$->membertype = MEMBER_METHOD;
$$->kind = $2;
$$->name = $4;
/* $$->emit = $10; */
$$->doc = $11;
};
const_def: T_CONST {
$$ = TRUE;
} | /* empty */ {
$$ = FALSE;
};
classbody: /* empty */ {
$$ = NULL;
} | classbody member_def{
$$ = g_slist_prepend($1, $2);
};
%%
#define YYDEBUG 1
GHashTable* type_hash;
GHashTable* class_hash;
int yyerror (char* s){
g_error ("Parser error: %s", s);
}