From c190a2ae41238682c1430b8482683b6a7c15c66b Mon Sep 17 00:00:00 2001 From: George Lebl Date: Mon, 12 Jul 1999 10:12:00 -0800 Subject: [PATCH] Release 0.0.1 --- AUTHORS | 1 + COPYING | 340 ++++++++++++++ Makefile | 8 + README | 42 ++ doc/USER_GUIDE | 211 +++++++++ src/Makefile | 29 ++ src/lexer.l | 209 +++++++++ src/main.c | 1148 ++++++++++++++++++++++++++++++++++++++++++++++++ src/parse.y | 582 ++++++++++++++++++++++++ src/test.gob | 67 +++ src/tree.c | 116 +++++ src/tree.h | 152 +++++++ 12 files changed, 2905 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 Makefile create mode 100644 README create mode 100644 doc/USER_GUIDE create mode 100644 src/Makefile create mode 100644 src/lexer.l create mode 100644 src/main.c create mode 100644 src/parse.y create mode 100644 src/test.gob create mode 100644 src/tree.c create mode 100644 src/tree.h diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..556d34a --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +George Lebl diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..eeb586b --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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 2 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..aa50670 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +all: + ( cd src && ${MAKE} ${MFLAGS} ) + +clean: + ( cd src && ${MAKE} ${MFLAGS} clean ) + +install: + ( cd src && ${MAKE} ${MFLAGS} install ) diff --git a/README b/README new file mode 100644 index 0000000..3c3d002 --- /dev/null +++ b/README @@ -0,0 +1,42 @@ +GTK+ Object Builder (GOB) + +Very early prototype. An extremely poor attempt at making a lex or yacc like +preprocessor for making GTK+ objects, while keeping he language in a sort of +java like style, and keeping the implementation extremely simple and without +having to parse any real C code. + +Reasons: + - C is a perfect (well mostly) language, no need for another language + - Writing a fully featured GTK+ object is a hassle + - Need for a generator that doesn't require changes to generated code + - I like how Java writes method code directly into the class + definition. + +To build: + run make + +To install: + edit the makefile to edit the destination directory and run + "make install" as root (or just put src/gob somewhere nice) + +To use: + run gob with the .gob file on the command line + +What's generated: + two (.c and .h) files named by the object name with words + separated by a hyphen (not neccessairly the .gob file prefix) + +How to write .gob files? + 1) read doc/USER_GUIDE for some documenation on how to use + GOB + 2) if you can't find what you need, read src/test.gob and + src/lexer.l and src/parse.y (in other words: RTFS) + +TODO: + - clean up code + - make it behave nice + - add warnings all over the place + - add autoconf/automake setup + - get a life + +George diff --git a/doc/USER_GUIDE b/doc/USER_GUIDE new file mode 100644 index 0000000..52ca71e --- /dev/null +++ b/doc/USER_GUIDE @@ -0,0 +1,211 @@ +GTK+ Object Builder + +AUTHOR: George Lebl + + GTK+ Object Builder is a simple preprocessor for easily creating +GTK+ objects. It does not parse any C code and ignores any C errors. It +is in spirit similiar to things like lex or yacc. + +Typenames: + + Because we need to parse out different parts of the typename, +sometimes you need to specify the typename with some special syntax. +Types are specified in capitalized form and words are separated by ':'. +The first word of the type (which can be empty) is the "namespace". This +fact is for example used for the type checking macro. For "Gtk:New:Button", +the macro will be GTK_IS_NEW_BUTTON. This format of typenames is used in +the class declaration header and for method argument types. + +The output file names: + + The filenames are created from the typename. The words are +separated by '-' and all in lower case. For example for an object named +"Gtk:New:Button", the files are gtk-new-button.c and gtk-new-button.h. + +Including normal C code in the output files: + + To include some code directly in the output C file begin with +'%{' on an empty line and end the code with a '%{' on an empty line. To +put the code in the output header file, start the code with a '%h{'. +For example: + +%h{ +void somefunc(int i); +%} +%{ +void somefunc(int i) +{ + /* some code */ +} +%} + +Making a new class: + +The class header: + + There can be only one class per input file. Defining a class +is sort of like in Java, you define the class and write inline code +directly into the class definition. To define a class you need to specify +the new object name and the name of the object from which it is derived +from, such as this "class from { }". +For example: + +class Gtk:New:Button from Gtk:Button { + +} + +Data members: + + There are three types of data members. Two of them are normal +data numbers, and one is a virtual one, usually linked to a normal public +data member. The two normal data members are public or private. They are +basically just copied into the object directly. There is only one +identifier allowed per typename unlike in normal C. Example: + +public int i; +private GtkWidget *h; + + The private members are not currently protected from outside use, +they are just marked by a comment in the header file, this will most likely +be somehow solved in some future version. + + The third type is an argument type. It is a named datamember which +is one of the features of the GTK+ object system. You need to define a get +and a set handler. They are fragments of C code that will be used to +get the value orset the value of the argument. Inside them you can use the +define ARG to which you assign the data or get the data. You can also use +the identifier "this" as pointer to the object instance. The type is +defined as one of the gtk type enums, but without the GTK_TYPE_ prefix. +For example: + +public int height; +argument INT height set { this->height = ARG; } get { ARG = this->height; }; + + If you don't define a set or a get handler it will be a readonly +or a writeonly argument. If you want to add extra argument flags, add +them into parenthesis after the argument keyword, separated by '|' and +without the GTK_ARG_ prefix. For example: + +public int height; +argument (CONSTRUCT) INT height get { ARG = this->height; }; + +Methods: + + There is a whole array of possible methods. The two normal, +"familiar" method types are private and public. Public are defined as +normal functions with a prototype in the header file. Private methods +are defined as static functions with prototypes at the top of the .c +file. Then there are signal, virtual and override methods. You can also +define init and init_class methods with a special definition if you want +to add code to the constructors or you can just leave them out. + +Argument lists: + + For all but the init and init_class methods, you use the +following syntax for arguments. The first argument can be just "this", +which gob will translateinto a pointer to the object instance. The rest +of the arguments are very similiar to normal C arguments. If the +typename is an object pointer you should use the syntax defined above +with the words separated by ':' + +or + (check ) + +The checks are glib type preconditions, and can be the following: +"null", which tests pointers for being NULL, "type" which checks GTK+ +object pointers for being the right type, " " which tests +numberic arguments for being a certain value. The test can be a <,>,<=,>= +!= or ==. Example: + +public int foo(this, int h (check > 0 < 11), Gtk:Widget *w (check null type)) + + This will be the prototype of a function which has a this pointer +as the first argument, an integer argument which will be checked and has +to be more then 0 and less then 11, and a pointer to a GtkWidget object +instance and it is checked for being null and the type will also be +checked. + +Error return: + + Methods which have a return value, there also has to be something +returned if there is an error, such as if a precondition is not met. The +default is 0, casted to the type of the method. If you need to return +something else then you can specify an "onerror" keyword after the +prototype and after that a number, a token (an identifier) or a bit of C +code enclosed in braces {}. The braces will not be printed into the +output, they just delimit the string. For example + +public void * get_something(this, int i (check >= 0)) onerror NULL { + ... +} + +Virtual methods: + + Virtual methods are basically pointers in the class structure, +so that one can override the method in derived methods. They can be empty +(if you put ';' instead of the C code). A wrapper will also be defined +which makes calling the methods he same as public methods. This type of +method is just a little bit "slower" then normal functions, but not as +slow as signals. You define them by using "virutal" keywrod before the +prototype. + +Signals: + + Signals are methods to which the user can bind other handlers +and override the default handler. The default handler is basically the +method body. This is the most versatile and flexible type of a method +and also the slowest. You need to specify a whole bunch of things when +you define a signal. One thing is when the default handler will be run, +first or last. You specify that by "first" or "last" right after the +"signal" keyword. Then you need to define the gtk enum types (again +without the GTK_TYPE_ prefix). For that you define the return types +and the types of arguments after the "this" pointer (not including the +"this" pointer). You put it in the following syntax " ()". If the return type is void, the type should be "NONE", +the same should be for the argument list. The rest of the prototype is +the same as for other method types. The body can also be empty, and +also there is a public method wrapper which you can use for calling the +signal jus tlike a public method. Example: + +signal first INT(POINTER,INT) +int do_something(this, Gtk:Widget *w (check null type), int length) +{ + ... +} + +or + +signal last NONE(NONE) void foo(this); + +Override methods: + + If you need to override some method (a signal or a virtual method +of some class in the parent tree of the new object), you can define and +override method. After the "override" keyword, you should put the +typename of the class you are overriding a method from. Other then that +it is the same as for other methods. The "this" pointer in this case +should be the type of the method you are overriding so that you don't +get warnings during compilation. Example: + +override (Gtk:Container) void +add (Gtk:Container *this (check null type), Gtk:Widget *wid (check null type)) +{ + ... +} + +Calling methods: + + Inside the code, defines are set for the methods, so that you don't +have to type the class name before each call. Example: + +private int +foo(this) +{ + return this->len; +} + +private int +bar(this,int i) +{ + return foo(this) + i; +} diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..cb90199 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,29 @@ +CC=gcc +CFLAGS=-g -Wall `glib-config --cflags` +LIBS=`glib-config --libs` -lfl -lpopt +YACC=bison -y +LEX=flex +DEST_DIR=/usr/local + +all: gob + +gob: main.o tree.o y.tab.o lex.yy.o + ${CC} ${LDFLAGS} -o $@ $^ ${LIBS} + +y.tab.c y.tab.h: parse.y + ${YACC} -d -t -v parse.y + +lex.yy.c: lexer.l + ${LEX} lexer.l + +parse.o: y.tab.h tree.h +lexer.o: y.tab.h tree.h +tree.o: tree.h +main.o: y.tab.h tree.h + +install: gob + install -d ${DEST_DIR}/bin + install -c gob ${DEST_DIR}/bin + +clean: + rm -f gob *.o y.tab.[ch] lex.yy.c y.output core diff --git a/src/lexer.l b/src/lexer.l new file mode 100644 index 0000000..92454f2 --- /dev/null +++ b/src/lexer.l @@ -0,0 +1,209 @@ +/* GOB C Preprocessor + * Copyright (C) 1999 the Free Software Foundation. + * + * Author: George Lebl + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +%{ + +#include + +#include "y.tab.h" + +static int parenth_depth = 0; +static int before_comment = INITIAL; +static int class_after_c = FALSE; +static int header_c = FALSE; + +static GString *cbuf = NULL; + +int line_no = 1; + +static void +clear_cbuf(void) +{ + if(!cbuf) { + cbuf = g_string_new(""); + } else { + cbuf = g_string_assign(cbuf,""); + } +} + +static void +add_to_cbuf(char *s) +{ + if(!cbuf) { + cbuf = g_string_new(s); + } else { + cbuf = g_string_append(cbuf,s); + } +} + +%} + +%x COMMENT +%x C_CODE +%x C_CODE_STRING +%x CLASS_CODE +%x CLASS_CODE_I + +%% + +<*>\n { line_no++; REJECT; } + +\/\/.*$ { ; /*comment, ignore*/ } +\/\/.*$ { ; /*comment, ignore*/ } +\/\/.*$ { ; /*comment, ignore*/ } +\/\/.*$ { ; /*comment, ignore*/ } +\/\* {BEGIN(COMMENT); before_comment = INITIAL; } +\/\* {BEGIN(COMMENT); before_comment = C_CODE; } +\/\* {BEGIN(COMMENT); before_comment = CLASS_CODE; } +\/\* {BEGIN(COMMENT); before_comment = CLASS_CODE_I; } +\*\/ {BEGIN(before_comment);} +. { ; /* comment, ignore */ } + +^\%h\{ { + BEGIN(C_CODE); + parenth_depth = 1; + class_after_c = FALSE; + header_c = TRUE; + clear_cbuf(); + } +^\%\{ { + BEGIN(C_CODE); + parenth_depth = 1; + class_after_c = FALSE; + header_c = FALSE; + clear_cbuf(); + } +^\%\} { + BEGIN(INITIAL); + yylval.cbuf = cbuf; + cbuf = NULL; + if(header_c) + return HCODE; + else + return CCODE; + } + +\'\{\' { add_to_cbuf(yytext); } +\'\\\{\' { add_to_cbuf(yytext); } +\'\}\' { add_to_cbuf(yytext); } +\'\\\}\' { add_to_cbuf(yytext); } + +\\. { add_to_cbuf(yytext); } +\" { + BEGIN(C_CODE_STRING); + add_to_cbuf(yytext); + } +\\. { + add_to_cbuf(yytext); + } +\" { + BEGIN(C_CODE); + add_to_cbuf(yytext); + } +. { + add_to_cbuf(yytext); + } + +\{ { + parenth_depth++; + add_to_cbuf(yytext); + } +\} { + parenth_depth--; + if(parenth_depth<0) { + REJECT; + } else if(parenth_depth==0 && class_after_c) { + BEGIN(CLASS_CODE_I); + yylval.cbuf = cbuf; + cbuf = NULL; + return CCODE; + } + add_to_cbuf(yytext); + } + +. { add_to_cbuf(yytext); } +\n { add_to_cbuf(yytext); } + +class { + BEGIN(CLASS_CODE); + return CLASS; + } + +from {return FROM;} + +void {return VOID;} +struct {return STRUCT;} +union {return UNION;} +enum {return ENUM;} +signed {return SIGNED;} +unsigned {return UNSIGNED;} +long {return LONG;} +short {return SHORT;} +int {return INT;} +float {return FLOAT;} +double {return DOUBLE;} +char {return CHAR;} + +public {yylval.line = line_no; return PUBLIC;} +private {yylval.line = line_no; return PRIVATE;} +argument {yylval.line = line_no; return ARGUMENT;} +virtual {yylval.line = line_no; return VIRTUAL;} +signal {yylval.line = line_no; return SIGNAL;} +last {return LAST;} +first {return FIRST;} +override {yylval.line = line_no; return OVERRIDE;} +check {return CHECK;} +null {return CNULL;} +type {return TYPE;} +onerror {return ONERROR;} +0|[1-9][0-9]*|0x[0-9a-fA-F]+|0[0-7]+|[0-9]*\.[0-9]+|\.[0-9][0-9]* { + yylval.id = g_strdup(yytext); + return NUMBER; + } +:?[A-Za-z_][A-Za-z0-9_]*(:[A-Za-z0-9_]*)+ { + yylval.id = g_strdup(yytext); + return TYPETOKEN; + } +[A-Za-z_][A-Za-z0-9_]* { + yylval.id = g_strdup(yytext); + return TOKEN; + } + +\{ { + BEGIN(CLASS_CODE_I); + return '{'; + } +\{ { + BEGIN(C_CODE); + parenth_depth=1; + class_after_c = TRUE; + return '{'; + } +\} { + BEGIN(INITIAL); + return '}'; + } + +[\n\t ] ; /*ignore*/ + +<*>. { + yylval.line = line_no; + return yytext[0]; + } diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..625f7bd --- /dev/null +++ b/src/main.c @@ -0,0 +1,1148 @@ +/* GOB C Preprocessor + * Copyright (C) 1999 the Free Software Foundation. + * + * Author: George Lebl + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include +#include +#include +#include +#include + +#include "tree.h" +#include "y.tab.h" + +#ifndef VERSION +#define VERSION "0.0.1" +#endif + +char *filename = "stdin"; + +int yyparse(void); + +extern int yydebug; +extern FILE * yyin; +extern Node *class; +extern GList *nodes; + +static char *filebase; +static char *funcbase; +static char *pfuncbase; +static char *macrobase; +static char *macrois; +static char *typebase; +static char *ptypebase; + +static FILE *out; +static FILE *outh; + +int exit_on_warn = FALSE; + +static void +print_error(int is_warn, char *error,int line) +{ + char *w; + if(is_warn) + w = "Warning:"; + else + w = "Error:"; + if(line>0) + fprintf(stderr,"%s:%d: %s %s\n",filename,line,w,error); + else + fprintf(stderr,"%s: %s %s\n",filename,w,error); + if(!is_warn || exit_on_warn) + exit(1); +} + +static char * +remove_sep(char *base) +{ + char *p; + char *s = g_strdup(base); + while((p=strchr(s,':'))) + strcpy(p,p+1); + return s; +} + +static char * +replace_sep(char *base, char r) +{ + char *p; + char *s = g_strdup(base); + while((p=strchr(s,':'))) + *p = r; + if(*s == r) { + p = g_strdup(s+1); + g_free(s); + return p; + } + return s; +} + +/*separate the namespace part and then replace rest of + separators with r*/ +static void +separns_replace_sep(char *base, char **ns, char **name, char r) +{ + char *p; + char *s = g_strdup(base); + *ns = NULL; + if((p=strchr(s,':')) && p!=s) { + *p = '\0'; + *ns = g_strdup(s); + p = g_strdup(p+1); + g_free(s); + s = p; + } + while((p=strchr(s,':'))) + *p = r; + if(*s == r) { + *name = g_strdup(s+1); + g_free(s); + } else + *name = s; +} + +static char * +make_is_macro(char *base) +{ + char *s1,*s2; + char *s; + + separns_replace_sep(base,&s1,&s2,'_'); + if(s1) + s = g_strconcat(s1,"_IS_",s2,NULL); + else + s = g_strconcat("IS_",s2,NULL); + + g_strup(s); + + g_free(s1); + g_free(s2); + + return s; +} + +static void +make_bases(void) +{ + filebase = replace_sep(((Class *)class)->otype,'-'); + g_strdown(filebase); + + funcbase = replace_sep(((Class *)class)->otype,'_'); + g_strdown(funcbase); + + pfuncbase = replace_sep(((Class *)class)->ptype,'_'); + g_strdown(pfuncbase); + + macrobase = replace_sep(((Class *)class)->otype,'_'); + g_strup(macrobase); + + macrois = make_is_macro(((Class *)class)->otype); + + typebase = remove_sep(((Class *)class)->otype); + + ptypebase = remove_sep(((Class *)class)->ptype); +} + +static void +def_methods(Class *c) +{ + GList *li; + + fprintf(out,"\n"); + for(li=c->nodes;li;li=g_list_next(li)) { + Node *node = li->data; + if(node->type == METHOD_NODE) { + Method *m = (Method *)node; + + if(m->scope == INIT_METHOD || + m->scope == CLASS_INIT_METHOD || + m->scope == OVERRIDE_METHOD) + continue; + + fprintf(out,"#define %s %s_%s\n",m->id,funcbase,m->id); + } + } + fprintf(out,"\n"); +} + +static void +undef_methods(Class *c) +{ + GList *li; + + fprintf(out,"\n"); + for(li=c->nodes;li;li=g_list_next(li)) { + Node *node = li->data; + if(node->type == METHOD_NODE) { + Method *m = (Method *)node; + + if(m->scope == INIT_METHOD || + m->scope == CLASS_INIT_METHOD || + m->scope == OVERRIDE_METHOD) + continue; + + fprintf(out,"#undef %s\n",m->id); + } + } + fprintf(out,"\n"); +} + +static void +print_type(FILE *fp, Type *t) +{ + char *s; + int i; + s = remove_sep(t->name); + fprintf(fp,"%s ",s); + g_free(s); + + for(i=0;istars;i++) + fprintf(fp,"*"); +} + +static void +put_variable(Variable *v) +{ + fprintf(outh,"\t"); + if(v->scope == PRIVATE_SCOPE) + fprintf(outh,"/* private */ "); + print_type(outh,v->vtype); + + fprintf(outh,"%s;\n",v->id); +} + +static void +print_method(FILE *fp, char *typeprefix, char *nameprefix, + char *namepostfix,char *postfix, Method *m) +{ + GList *li; + + fprintf(fp,"%s",typeprefix); + print_type(fp,m->mtype); + fprintf(fp,"%s%s_%s%s(", + nameprefix,funcbase,m->id,namepostfix); + + for(li=m->args;li;li=g_list_next(li)) { + FuncArg *arg = li->data; + print_type(fp,arg->atype); + if(li->next) + fprintf(fp,"%s, ",arg->name); + else + fprintf(fp,"%s",arg->name); + + } + fprintf(fp,")%s\n",postfix); +} + +static void +put_vs_method(Method *m) +{ + if(m->scope != SIGNAL_LAST_METHOD && + m->scope != SIGNAL_FIRST_METHOD && + m->scope != VIRTUAL_METHOD) + return; + + print_method(outh,"\t","(* ",") ",";",m); +} + +static void +put_pub_method(Method *m) +{ + if(m->scope == PRIVATE_SCOPE || + m->scope == OVERRIDE_METHOD || + m->scope == INIT_METHOD || + m->scope == CLASS_INIT_METHOD) + return; + + print_method(outh,"\t","","\t",";",m); +} + +static void +put_priv_method_prot(Method *m) +{ + if(m->scope == PUBLIC_SCOPE) + return; + + if(m->scope == SIGNAL_LAST_METHOD || + m->scope == SIGNAL_FIRST_METHOD || + m->scope == VIRTUAL_METHOD) { + if(!m->cbuf) + return; + print_method(out,"static ","_real_"," ",";",m); + } else { + print_method(out,"static ",""," ",";",m); + } +} + +static GList * +make_init_args(Class *cl, char *name, int is_class) +{ + Node *node; + Node *type; + char *tn; + + if(is_class) + tn = g_strconcat(cl->otype,":Class",NULL); + else + tn = g_strdup(cl->otype); + + type = new_type(1,tn); + node = new_funcarg((Type *)type,name,NULL); + return g_list_prepend(NULL, node); +} + +static void +make_inits(Class *cl) +{ + int got_class_init = FALSE; + int got_init = FALSE; + GList *li; + Node *node; + for(li=cl->nodes;li;li=g_list_next(li)) { + Node *n = li->data; + if(n->type == METHOD_NODE) { + Method *m = (Method *)n; + if(m->scope == INIT_METHOD) { + if(got_init) + print_error(FALSE,"init defined more then once",m->line_no); + got_init = TRUE; + } else if(m->scope == CLASS_INIT_METHOD) { + if(got_class_init) + print_error(FALSE,"class_init defined more then once",m->line_no); + got_class_init = TRUE; + } + } + } + if(!got_class_init) { + node = new_method(CLASS_INIT_METHOD, + (Type *)new_type(0,g_strdup("void")), + NULL,NULL,g_strdup("class_init"), + make_init_args(cl,g_strdup("c"),TRUE), + NULL, NULL,0); + cl->nodes = g_list_prepend(cl->nodes,node); + } + if(!got_init) { + node = new_method(INIT_METHOD, + (Type *)new_type(0,g_strdup("void")), + NULL,NULL,g_strdup("init"), + make_init_args(cl,g_strdup("o"),FALSE), + NULL, NULL,0); + cl->nodes = g_list_prepend(cl->nodes,node); + } +} + +static GHashTable *marsh = NULL; + +static void +add_signal_prots(Method *m) +{ + GList *li; + static int sig = 1; + char *s; + + if(m->scope != SIGNAL_LAST_METHOD && + m->scope != SIGNAL_FIRST_METHOD) + return; + + if(!marsh) + marsh = g_hash_table_new(NULL,NULL); + + if(strcmp(m->gtktypes->data,"NONE")==0 && + strcmp(m->gtktypes->next->data,"NONE")==0) + return; + + s = g_strdup_printf("__Sig%d",sig++); + + g_hash_table_insert(marsh,m,s); + + fprintf(out,"\ntypedef "); + print_type(out,m->mtype); + + fprintf(out,"(*%s) (",s); + + for(li=m->args;li;li=g_list_next(li)) { + FuncArg *arg = li->data; + print_type(out,arg->atype); + fprintf(out,", "); + } + fprintf(out,"gpointer);\n"); + + fprintf(out,"\nstatic void\n" + "marshal_%s (GtkObject * object,\n" + "\tGtkSignalFunc func,\n" + "\tgpointer func_data,\n" + "\tGtkArg * args)\n" + "{\n",s); + + if(strcmp(m->gtktypes->data,"NONE")==0) { + int i; + fprintf(out, "\t%s rfunc;\n\n" + "\trfunc = (%s)func;\n\n" + "\t(*rfunc)((%s *)object",s,s,typebase); + if(strcmp(m->gtktypes->next->data,"NONE")!=0) { + for(i=0,li=m->gtktypes->next;li; + i++,li=g_list_next(li)) { + fprintf(out, ",\n\t\tGTK_VALUE_%s(args[%d])", + (char *)li->data,i); + } + } + fprintf(out, ",\n\t\tfunc_data);\n}\n\n"); + } else { + int i; + fprintf(out, "\t%s rfunc;\n\t",s); + print_type(out,m->mtype); + fprintf(out, " *retval;\n\n" + "\trfunc = (%s)func;\n\n" + "\tretval = GTK_RETLOC_%s(args[%d]);\n\n" + "\t*retval = (*rfunc)((%s *)object", + s,(char *)m->gtktypes->data, + g_list_length(m->gtktypes)-1,typebase); + if(strcmp(m->gtktypes->next->data,"NONE")!=0) { + for(i=0,li=m->gtktypes->next;li; + i++,li=g_list_next(li)) { + fprintf(out, ",\n\t\tGTK_VALUE_%s(args[%d])", + (char *)li->data,i); + } + } + fprintf(out, ",\n\t\tfunc_data);\n}\n\n"); + } + +} + +static void +add_enums(Class *c) +{ + GList *li; + fprintf(out,"\nenum {\n"); + for(li=c->nodes;li;li=g_list_next(li)) { + Node *n = li->data; + if(n->type == METHOD_NODE) { + Method *m = (Method *)n; + if(m->scope == SIGNAL_LAST_METHOD || + m->scope == SIGNAL_FIRST_METHOD) { + char *s = g_strdup(m->id); + g_strup(s); + fprintf(out,"\t%s_SIGNAL,\n",s); + g_free(s); + } + } + } + fprintf(out,"\tLAST_SIGNAL\n" + "};\n\n" + "enum {\n" + "\tARG_0,\n"); + for(li=c->nodes;li;li=g_list_next(li)) { + Node *n = li->data; + if(n->type == ARGUMENT_NODE) { + Argument *a = (Argument *)n; + char *s = g_strdup(a->name); + g_strup(s); + fprintf(out,"\tARG_%s,\n",s); + g_free(s); + } + } + fprintf(out, "};\n\n" + "static guint object_signals[LAST_SIGNAL] = {0};\n\n" + "static %sClass *parent_class = NULL;\n\n",ptypebase); +} + +static void +add_get_type(void) +{ + fprintf(out, "guint\n" + "%s_get_type (void)\n" + "{\n" + "\tstatic guint type = 0;\n\n" + "\tif (!type) {\n" + "\t\tstatic const GtkTypeInfo info = {\n" + "\t\t\t\"%s\",\n" + "\t\t\tsizeof (%s),\n" + "\t\t\tsizeof (%sClass),\n" + "\t\t\t(GtkClassInitFunc) %s_class_init,\n" + "\t\t\t(GtkObjectInitFunc) %s_init,\n" + "\t\t\t/* reserved_1 */ NULL,\n" + "\t\t\t/* reserved_2 */ NULL,\n" + "\t\t\t(GtkClassInitFunc) NULL,\n" + "\t\t};\n\n" + "\t\ttype = gtk_type_unique (%s_get_type(), &info);\n" + "\t}\n\n" + "\treturn type;\n" + "}\n\n", + funcbase,typebase,typebase,typebase, + funcbase,funcbase,pfuncbase); +} + +static void +add_overrides(Class *c, char *oname) +{ + GList *li; + GHashTable *done; + char *s; + + done = g_hash_table_new(g_str_hash,g_str_equal); + s = g_strdup("GtkObject"); /* This was already done */ + g_hash_table_insert(done,s,s); + for(li=c->nodes;li;li=g_list_next(li)) { + Node *n = li->data; + char *f; + Method *m; + if(n->type != METHOD_NODE || + ((Method *)n)->scope != OVERRIDE_METHOD) + continue; + m = (Method *)n; + + s = remove_sep(m->otype); + + if(g_hash_table_lookup(done,s)) { + g_free(s); + continue; + } + g_hash_table_insert(done,s,s); + + f = replace_sep(m->otype,'_'); + g_strdown(f); + + fprintf(out,"\t%sClass *%s_class = (%sClass *)%s;\n", + s,f,s,oname); + + g_free(f); + } + g_hash_table_foreach(done,(GHFunc)g_free,NULL); + g_hash_table_destroy(done); +} + +static void +add_signals(Class *c) +{ + GList *li; + + fprintf(out,"\n"); + for(li=c->nodes;li;li=g_list_next(li)) { + Node *n = li->data; + Method *m; + char *mar; + char *sig; + int is_none; + if(n->type != METHOD_NODE || + (((Method *)n)->scope != SIGNAL_FIRST_METHOD && + ((Method *)n)->scope != SIGNAL_LAST_METHOD)) + continue; + + m = (Method *)n; + + if(g_hash_table_lookup(marsh,m)) + mar = g_strconcat("marshal_", + (char *)g_hash_table_lookup(marsh,m), + NULL); + else + mar = g_strdup("gtk_signal_default_marshaller"); + + is_none = (strcmp(m->gtktypes->next->data,"NONE")==0); + + sig = g_strdup(m->id); + g_strup(sig); + fprintf(out,"\tobject_signals[%s_SIGNAL] =\n" + "\t\tgtk_signal_new (\"%s\",\n" + "\t\t\tGTK_RUN_%s,\n" + "\t\t\tgtk_object_class->type,\n" + "\t\t\tGTK_SIGNAL_OFFSET (%sClass, %s),\n" + "\t\t\t%s,\n" + "\t\t\tGTK_TYPE_%s, %d", + sig,m->id, + m->scope==SIGNAL_LAST_METHOD?"LAST":"FIRST", + typebase,m->id,mar,(char *)m->gtktypes->data, + is_none?0:g_list_length(m->gtktypes->next)); + g_free(mar); + g_free(sig); + + if(!is_none) { + GList *l; + for(l=m->gtktypes->next;l;l=g_list_next(l)) + fprintf(out,",\n\t\t\tGTK_TYPE_%s", + (char *)l->data); + } + + fprintf(out,");\n"); + } + fprintf(out,"\tgtk_object_class_add_signals (gtk_object_class,\n" + "\t\tobject_signals, LAST_SIGNAL);\n\n"); +} + +static void +set_def_handlers(Class *c, char *oname) +{ + GList *li; + + fprintf(out,"\n"); + for(li=c->nodes;li;li=g_list_next(li)) { + Node *n = li->data; + Method *m; + if(n->type != METHOD_NODE || + (((Method *)n)->scope != SIGNAL_FIRST_METHOD && + ((Method *)n)->scope != SIGNAL_LAST_METHOD && + ((Method *)n)->scope != VIRTUAL_METHOD && + ((Method *)n)->scope != OVERRIDE_METHOD)) + continue; + + m = (Method *)n; + + if(m->scope == OVERRIDE_METHOD) { + char *s; + s = replace_sep(m->otype,'_'); + g_strdown(s); + fprintf(out,"\t%s_class->%s = %s_%s;\n", + s,m->id,funcbase,m->id); + } else { + if(m->cbuf) + fprintf(out,"\t%s->%s = _real_%s_%s;\n", + oname,m->id,funcbase,m->id); + else + fprintf(out,"\t%s->%s = NULL;\n", + oname,m->id); + } + } +} + +static void +make_arguments(Class *c) +{ + GList *li; + + fprintf(out,"\n"); + for(li=c->nodes;li;li=g_list_next(li)) { + Node *n = li->data; + Argument *a; + GString *flags; + GList *l; + char *s; + if(n->type != ARGUMENT_NODE) + continue; + + a = (Argument *)n; + + if(a->get && a->set) + flags = g_string_new("GTK_ARG_READWRITE"); + else if(a->get) + flags = g_string_new("GTK_ARG_READABLE"); + else + flags = g_string_new("GTK_ARG_WRITABLE"); + + for(l=a->flags;l;l=g_list_next(l)) + g_string_sprintfa(flags," | GTK_ARG_%s",(char *)l->data); + + s = g_strdup(a->name); + g_strup(s); + fprintf(out,"\tgtk_object_add_arg_type(\"%s::%s\",\n" + "\t\tGTK_TYPE_%s,\n" + "\t\t%s,\n" + "\t\tARG_%s);\n", + typebase,a->name,a->gtktype,flags->str,s); + g_free(s); + g_string_free(flags,TRUE); + } + + fprintf(out,"\n\tgtk_object_class->set_arg = __object_set_arg;\n" + "\tgtk_object_class->get_arg = __object_get_arg;\n"); +} + +static void +add_inits(Class *c) +{ + GList *li; + for(li=c->nodes;li;li=g_list_next(li)) { + Node *n = li->data; + Method *m; + if(n->type != METHOD_NODE) + continue; + m = (Method *)n; + if(m->scope == INIT_METHOD) { + print_method(out,"static ","\n"," ","",m); + if(m->cbuf) + fprintf(out,"{\n%s\n}\n\n",m->cbuf->str); + else + fprintf(out,"{\n\treturn;\n}\n\n"); + } else if(m->scope == CLASS_INIT_METHOD) { + print_method(out,"static ","\n"," ","",m); + fprintf(out,"{\n" + "\tGtkObjectClass *gtk_object_class = " + "(GtkObjectClass*) %s;\n", + ((FuncArg *)m->args->data)->name); + + add_overrides(c, ((FuncArg *)m->args->data)->name); + + fprintf(out,"\n\tparent_class = " + "gtk_type_class (%s_get_type ());\n", + pfuncbase); + + add_signals(c); + + set_def_handlers(c, ((FuncArg *)m->args->data)->name); + + make_arguments(c); + + if(m->cbuf) + fprintf(out," {\n%s\n }\n",m->cbuf->str); + fprintf(out,"}\n"); + } + } +} + +static void +add_getset_arg(Class *c, int is_set) +{ + GList *li; + fprintf(out,"\nstatic void\n" + "__object_%s_arg (GtkObject *object,\n" + "\tGtkArg *arg,\n" + "\tguint arg_id)\n" + "{\n" + "\t%s *this;\n\n" + "\tthis = %s (object);\n\n" + "\tswitch (arg_id) {\n", + is_set?"set":"get",typebase,macrobase); + + for(li=c->nodes;li;li=g_list_next(li)) { + Node *n = li->data; + Argument *a; + char *s; + if(n->type != ARGUMENT_NODE) + continue; + a = (Argument *)n; + if((is_set && !a->set) || + (!is_set && !a->get)) + continue; + s = g_strdup(a->name); + g_strup(s); + fprintf(out,"\tcase ARG_%s:\n" + "#define ARG (GTK_VALUE_%s(*arg))\n" + "\t\t{\n%s\n\t\t}\n\t\tbreak;\n" + "#undef ARG\n", + s,a->gtktype,a->set->str); + g_free(s); + } + fprintf(out,"\tdefault:\n\t\tbreak;\n\t}\n}\n"); +} + +static void +print_checks(Method *m, FuncArg *fa) +{ + GList *li; + int is_void; + is_void = (strcmp(m->mtype->name,"void")==0 && + m->mtype->stars == 0); + + for(li=fa->checks;li;li=g_list_next(li)) { + Check *ch = li->data; + char *s; + if(is_void) + fprintf(out,"\tg_return_if_fail ("); + else + fprintf(out,"\tg_return_val_if_fail ("); + switch(ch->chtype) { + case NULL_CHECK: + fprintf(out,"%s != NULL",fa->name); + break; + case TYPE_CHECK: + s = make_is_macro(fa->atype->name); + fprintf(out,"%s (%s)",s,fa->name); + g_free(s); + break; + case LT_CHECK: + fprintf(out,"%s < %s",fa->name,ch->number); + break; + case GT_CHECK: + fprintf(out,"%s > %s",fa->name,ch->number); + break; + case LE_CHECK: + fprintf(out,"%s <= %s",fa->name,ch->number); + break; + case GE_CHECK: + fprintf(out,"%s >= %s",fa->name,ch->number); + break; + case EQ_CHECK: + fprintf(out,"%s == %s",fa->name,ch->number); + break; + case NE_CHECK: + fprintf(out,"%s != %s",fa->name,ch->number); + break; + } + if(is_void) + fprintf(out,");\n"); + else { + fprintf(out,", ("); + print_type(out,m->mtype); + fprintf(out,")%s);\n", + m->onerror?m->onerror:"0"); + } + } +} + +static void +print_preconditions(Method *m) +{ + GList *li; + + for(li=m->args;li;li=g_list_next(li)) { + FuncArg *fa = li->data; + if(fa->checks) + print_checks(m,fa); + } +} + +static void +print_method_body(Method *m, int pre) +{ + fprintf(out,"{\n"); + if(pre) { + print_preconditions(m); + fprintf(out,"\t{\n"); + } + + fprintf(out,"\t\t%s\n",m->cbuf->str); + + if(pre) + fprintf(out,"\t}\n"); + fprintf(out,"}\n"); +} + +static void +put_method(Method *m) +{ + char *s; + fprintf(out,"\n"); + if(strcmp(m->id,"new")==0) { + fprintf(out,"#define GET_NEW (gtk_type_new(%s_get_type()))\n", + funcbase); + } + switch(m->scope) { + case PUBLIC_SCOPE: + print_method(out,"","\n"," ","",m); + print_method_body(m,TRUE); + break; + case PRIVATE_SCOPE: + print_method(out,"static ","\n"," ","",m); + print_method_body(m,TRUE); + break; + case SIGNAL_FIRST_METHOD: + case SIGNAL_LAST_METHOD: + print_method(out,"","\n"," ","",m); + fprintf(out,"{\n"); + s = g_strdup(m->id); + g_strup(s); + if(strcmp(m->mtype->name,"void")==0 && + m->mtype->stars==0) { + GList *li; + print_preconditions(m); + fprintf(out,"\tgtk_signal_emit (GTK_OBJECT (this),\n" + "\t\tobject_signals[%s_SIGNAL]",s); + for(li=m->args->next;li;li=g_list_next(li)) { + FuncArg *fa = li->data; + fprintf(out,",\n\t\t%s",fa->name); + } + fprintf(out,");\n}\n"); + } else { + GList *li; + fprintf(out,"\t"); + print_type(out,m->mtype); + fprintf(out,"return_val;\n"); + print_preconditions(m); + fprintf(out,"\tgtk_signal_emit (GTK_OBJECT (this),\n" + "\t\tobject_signals[%s_SIGNAL]",s); + for(li=m->args->next;li;li=g_list_next(li)) { + FuncArg *fa = li->data; + fprintf(out,",\n\t\t%s",fa->name); + } + fprintf(out,",\n\t\t&return_val);\n" + "\treturn return_val;\n}\n"); + } + + if(!m->cbuf) + break; + print_method(out,"static ","\n_real_"," ","",m); + print_method_body(m,FALSE); + break; + case VIRTUAL_METHOD: + print_method(out,"","\n"," ","",m); + fprintf(out,"{\n" + "\t%sClass *class;\n",typebase); + print_preconditions(m); + fprintf(out,"\tclass = %s_CLASS(GTK_OBJECT(this)->klass);\n\n" + "\tif(class->%s)\n", + macrobase,m->id); + if(strcmp(m->mtype->name,"void")==0 && + m->mtype->stars==0) { + GList *li; + fprintf(out,"\t\t(*class->%s)(this",m->id); + for(li=m->args->next;li;li=g_list_next(li)) { + FuncArg *fa = li->data; + fprintf(out,",%s",fa->name); + } + fprintf(out,");\n}\n"); + } else { + GList *li; + fprintf(out,"\t\treturn (*class->%s)(this",m->id); + for(li=m->args->next;li;li=g_list_next(li)) { + FuncArg *fa = li->data; + fprintf(out,",%s",fa->name); + } + fprintf(out,");\n" + "\telse\n" + "\t\treturn ("); + print_type(out,m->mtype); + fprintf(out,")(%s);\n}\n", + m->onerror?m->onerror:"0"); + } + + if(!m->cbuf) + break; + print_method(out,"static ","\n_real_"," ","",m); + print_method_body(m,FALSE); + break; + case OVERRIDE_METHOD: + print_method(out,"static ","\n"," ","",m); + print_method_body(m,TRUE); + break; + default: + break; + } + if(strcmp(m->id,"new")==0) + fprintf(out,"#undef GET_NEW\n"); +} + +static void +open_files(void) +{ + char *outfile,*outfileh; + + outfile = g_strconcat(filebase,".c",NULL); + outfileh = g_strconcat(filebase,".h",NULL); + + out = fopen(outfile,"w"); + if(!out) { + g_error("Cannot open outfile: %s",outfile); + } + outh = fopen(outfileh,"w"); + if(!outh) { + g_error("Cannot open outfile: %s",outfileh); + } +} + +static void +generate_outfiles(void) +{ + char *p; + GList *li; + time_t curtime; + + time(&curtime); + fprintf(outh,"/* Generated by GOB (v%s) on %s" + " (do not edit directly) */\n\n",VERSION,ctime(&curtime)); + fprintf(out,"/* Generated by GOB (v%s) on %s" + " (do not edit directly) */\n\n",VERSION,ctime(&curtime)); + + p = replace_sep(((Class *)class)->otype,'_'); + g_strup(p); + fprintf(outh,"#ifndef __%s_H__\n#define __%s_H__\n\n" + "#include \n\n",p,p); + g_free(p); + + fprintf(outh,"#ifdef __cplusplus\n" + "extern \"C\" {\n" + "#endif /* __cplusplus */\n\n"); + + fprintf(out,"#include \"%s.h\"\n\n",filebase); + + for(li=nodes;li;li=g_list_next(li)) { + Node *node = li->data; + if(node->type == CCODE_NODE) { + CCode *cc = (CCode *)node; + FILE *fp; + if(cc->header) + fp = outh; + else + fp = out; + fprintf(fp,"\n%s\n",cc->cbuf->str); + } else if(node->type == CLASS_NODE) { + GList *l; + Class *c = (Class *)class; + char *otype,*ptype; + + fprintf(outh,"\n#define %s(obj)\t" + "GTK_CHECK_CAST((obj),%s_get_type(),%s)\n", + macrobase,funcbase,typebase); + fprintf(outh,"#define %s_CLASS(klass)\t" + "GTK_CHECK_CLASS_CAST((klass),%s_get_type(),%sClass)\n", + macrobase,funcbase,typebase); + fprintf(outh,"#define %s(obj)\t" + "GTK_CHECK_TYPE((obj), %s_get_type ())\n\n", + macrois,funcbase); + + otype = remove_sep(c->otype); + ptype = remove_sep(c->ptype); + fprintf(outh,"\ntypedef struct _%s %s;\n",otype,otype); + fprintf(outh,"struct _%s {\n\t%s __parent__;\n", + otype,ptype); + for(l=c->nodes;l;l=g_list_next(l)) { + Node *n = l->data; + if(n->type == VARIABLE_NODE) + put_variable((Variable *)n); + } + fprintf(outh,"};\n"); + + fprintf(outh,"\ntypedef struct _%sClass %sClass;\n", + otype,otype); + fprintf(outh, + "struct _%sClass {\n\t%sClass __parent__;\n", + otype,ptype); + for(l=c->nodes;l;l=g_list_next(l)) { + Node *n = l->data; + if(n->type == METHOD_NODE) + put_vs_method((Method *)n); + } + fprintf(outh,"};\n\n"); + + fprintf(outh,"guint\t%s_get_type\t(void);\n",funcbase); + + fprintf(out,"static void __object_set_arg " + "(GtkObject *object, GtkArg *arg, " + "guint arg_id);\n" + "static void __object_get_arg " + "(GtkObject *object, GtkArg *arg, " + "guint arg_id);\n"); + + for(l=c->nodes;l;l=g_list_next(l)) { + Node *n = l->data; + if(n->type == METHOD_NODE) { + put_pub_method((Method *)n); + put_priv_method_prot((Method *)n); + } + } + + for(l=c->nodes;l;l=g_list_next(l)) { + Node *n = l->data; + if(n->type == METHOD_NODE) { + add_signal_prots((Method *)n); + } + } + + add_enums(c); + + add_get_type(); + + def_methods(c); + + add_inits(c); + + add_getset_arg(c, TRUE); + add_getset_arg(c, FALSE); + + for(l=c->nodes;l;l=g_list_next(l)) { + Node *n = l->data; + if(n->type == METHOD_NODE) { + put_method((Method *)n); + } + } + + undef_methods(c); + + g_free(otype); + g_free(ptype); + } else + g_assert_not_reached(); + } + + fprintf(outh,"\n#ifdef __cplusplus\n" + "}\n" + "#endif /* __cplusplus */\n\n" + "#endif"); +} + +static void +usage(poptContext optCon, int exitcode, char *error, char *addl) +{ + poptPrintUsage(optCon, stderr, 0); + if (error) fprintf(stderr, "%s: %s", error, addl); + exit(exitcode); +} + + +int +main(int argc, char *argv[]) +{ + int c; + poptContext optCon; + + struct poptOption optionsTable[] = { + { "exit-on-warn", 'w', 0, &exit_on_warn, 0, + "exit on warnings" }, + POPT_AUTOHELP + { NULL, 0, 0, NULL, 0 } + }; + + optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); + poptSetOtherOptionHelp(optCon, "[OPTIONS]* [filename]"); + + while ((c = poptGetNextOpt(optCon)) >= 0) + ; + + filename = poptGetArg(optCon); + if(!(poptPeekArg(optCon) == NULL)) + usage(optCon, 1, "Specify only one file", + ".e.g., filename.gob"); + + if (c < -1) { + /* an error occurred during option processing */ + fprintf(stderr, "%s: %s\n", + poptBadOption(optCon, POPT_BADOPTION_NOALIAS), + poptStrerror(c)); + return 1; + } + + if(filename) { + yyin = fopen(filename,"r"); + if(!yyin) { + fprintf(stderr,"Error: can't open file '%s'\n", + filename); + exit(1); + } + } else + filename = "stdin"; + + /*yydebug = 1;*/ + if(yyparse()!=0) + g_error("Parsing errors, quitting"); + if(!class) + print_error(FALSE," no class defined",0); + + make_bases(); + + make_inits((Class *)class); + + open_files(); + + generate_outfiles(); + + fclose(out); + fclose(outh); + + poptFreeContext(optCon); + return 0; +} diff --git a/src/parse.y b/src/parse.y new file mode 100644 index 0000000..9ce92de --- /dev/null +++ b/src/parse.y @@ -0,0 +1,582 @@ +/* GOB C Preprocessor + * Copyright (C) 1999 the Free Software Foundation. + * + * Author: George Lebl + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +%{ + +#include +#include +#include + +#include "tree.h" + +#define _(x) (x) + +extern char *filename; + +GList *nodes = NULL; + +static GList *class_nodes = NULL; +Node *class = NULL; + +static GList *typestack = NULL; +static int stars = 0; +static GList *funcargs = NULL; +static GList *checks = NULL; +static int has_this = FALSE; + +static GList *gtktypes = NULL; + +void free(void *ptr); +int yylex(void); + +extern int line_no; + +extern char *yytext; + +static void +yyerror(char *str) +{ + char *out=NULL; + char *p; + + if(strcmp(yytext,"\n")==0) { + out=g_strconcat("Error: ",str," before newline",NULL); + } else if(yytext[0]=='\0') { + out=g_strconcat("Error: ",str," at end of input",NULL); + } else { + char *tmp = g_strdup(yytext); + while((p=strchr(tmp,'\n'))) + *p='.'; + + out=g_strconcat("Error: ",str," before '",tmp,"'",NULL); + g_free(tmp); + } + + fprintf(stderr,"%s:%d: %s\n",filename,line_no,out); + g_free(out); + + exit(1); +} + +static void +push_variable(char *name, int scope) +{ + Node *var; + Type *type = typestack->data; + typestack = g_list_remove(typestack,typestack->data); + + var = new_variable(scope,type,name); + class_nodes = g_list_append(class_nodes, var); +} + +static void +push_function(int scope, char *oid, char *id, char *onerror, + GString *cbuf,int line_no) +{ + Node *node; + Type *type; + + if(scope!=INIT_METHOD && scope!=CLASS_INIT_METHOD) { + type = typestack->data; + typestack = g_list_remove(typestack,typestack->data); + } else { + type = (Type *)new_type(0,g_strdup("void")); + } + + node = new_method(scope,type,oid,gtktypes,id,funcargs, + onerror,cbuf,line_no); + gtktypes = NULL; + funcargs = NULL; + + class_nodes = g_list_append(class_nodes, node); +} + +static void +push_funcarg(char *name) +{ + Node *node; + Type *type = typestack->data; + typestack = g_list_remove(typestack,typestack->data); + + node = new_funcarg(type,name,checks); + checks = NULL; + + funcargs = g_list_append(funcargs, node); +} + +static void +push_init_arg(char *name, int is_class) +{ + Node *node; + Node *type; + char *tn; + + if(is_class) + tn = g_strconcat(((Class *)class)->otype,":Class",NULL); + else + tn = g_strdup(((Class *)class)->otype); + + type = new_type(1,tn); + node = new_funcarg((Type *)type,name,NULL); + funcargs = g_list_prepend(funcargs, node); +} + +static void +push_this(char *this) +{ + Node *node; + Node *type; + GList *ch = NULL; + type = new_type(1,g_strdup(((Class *)class)->otype)); + ch = g_list_append(ch,new_check(NULL_CHECK,NULL)); + ch = g_list_append(ch,new_check(TYPE_CHECK,NULL)); + node = new_funcarg((Type *)type,this,ch); + funcargs = g_list_prepend(funcargs, node); +} + +%} + +%union { + char *id; + GString *cbuf; + GList *list; + int line; +} + +%token CLASS FROM +%token VOID STRUCT UNION ENUM SIGNED UNSIGNED LONG SHORT INT FLOAT DOUBLE CHAR +%token FIRST LAST +%token CHECK CNULL TYPE ONERROR + +%token TOKEN NUMBER TYPETOKEN +%token CCODE HCODE +%token PUBLIC PRIVATE ARGUMENT VIRTUAL SIGNAL OVERRIDE + +%% + +prog: ccodes class ccodes { ; } + | class ccodes { ; } + | ccodes class { ; } + | class { ; } + ; + +ccodes: ccodes CCODE { + Node *node = new_ccode(FALSE,$2); + nodes = g_list_append(nodes,node); + } + | ccodes HCODE { + Node *node = new_ccode(TRUE,$2); + nodes = g_list_append(nodes,node); + } + | CCODE { + Node *node = new_ccode(FALSE,$1); + nodes = g_list_append(nodes,node); + } + | HCODE { + Node *node = new_ccode(TRUE,$1); + nodes = g_list_append(nodes,node); + } + ; + +class: classdec '{' classcode '}' { + ((Class *)class)->nodes = class_nodes; + class_nodes = NULL; + nodes = g_list_append(nodes,class); + } + ; + +classdec: CLASS TYPETOKEN FROM TYPETOKEN { + class = new_class($2,$4,NULL); + } + ; + +classcode: classcode method { ; } + | classcode variable { ; } + | classcode argument { ; } + | method { ; } + | variable { ; } + | argument { ; } + ; + +variable: PUBLIC type TOKEN ';' { + push_variable($3,PUBLIC_SCOPE); + } + | PRIVATE type TOKEN ';' { + push_variable($3,PRIVATE_SCOPE); + } + ; +argument: ARGUMENT argflags TOKEN TOKEN TOKEN '{' CCODE TOKEN '{' CCODE ';' { + if(strcmp($5,"get")==0 && + strcmp($8,"set")==0) { + Node *node; + g_free($5); g_free($8); + node = new_argument($3,$2,$4, + $7,$10); + class_nodes = g_list_append(class_nodes,node); + } else if(strcmp($5,"set")==0 && + strcmp($8,"get")==0) { + Node *node; + g_free($5); g_free($8); + node = new_argument($3,$2,$4, + $10,$7); + class_nodes = g_list_append(class_nodes,node); + } else { + g_free($3); g_free($4); + g_free($5); g_free($8); + g_list_foreach($2,(GFunc)g_free,NULL); + g_string_free($10,TRUE); + g_string_free($7,TRUE); + yyerror(_("parse error")); + YYERROR; + } + } + | ARGUMENT argflags TOKEN TOKEN TOKEN '{' CCODE ';' { + if(strcmp($5,"get")==0) { + Node *node; + g_free($5); + node = new_argument($3,$2,$4, + $7,NULL); + class_nodes = g_list_append(class_nodes,node); + } else if(strcmp($5,"set")==0) { + Node *node; + g_free($5); + node = new_argument($3,$2,$4, + NULL,$7); + class_nodes = g_list_append(class_nodes,node); + } else { + g_free($5); g_free($3); + g_free($4); + g_list_foreach($2,(GFunc)g_free,NULL); + g_string_free($7,TRUE); + yyerror(_("parse error")); + YYERROR; + } + } + ; + +argflags: '(' flaglist ')' { $$ = $2; } + | { $$ = NULL; } + ; + +flaglist: TOKEN '|' flaglist { + $$ = g_list_append($3,$1); + } + | TOKEN { + $$ = g_list_append(NULL,$1); + } + ; + + +type: type1 { + Node *node = new_type(0,$1); + typestack = g_list_prepend(typestack,node); + } + | type1 stars { + Node *node = new_type(stars,$1); + stars = 0; + typestack = g_list_prepend(typestack,node); + } + ; + +type1: UNSIGNED integer { + $$ = g_strconcat("unsigned ",$2,NULL); + } + | SIGNED integer { + $$ = g_strconcat("signed ",$2,NULL); + } + | integer { + $$ = g_strdup($1); + } + | UNSIGNED CHAR { + $$ = g_strdup("unsigned char"); + } + | SIGNED CHAR { + $$ = g_strdup("signed char"); + } + | DOUBLE { + $$ = g_strdup("double"); + } + | FLOAT { + $$ = g_strdup("float"); + } + | TOKEN { + $$ = $1; + } + | tspecifier TOKEN { + $$ = g_strconcat($1,$2,NULL); + g_free($2); + } + | TYPETOKEN { + $$ = $1; + } + | VOID { + $$ = g_strdup("void"); + } + ; + +integer: LONG INT { + $$ = "long int"; + } + | LONG { + $$ = "long"; + } + | SHORT INT { + $$ = "short int"; + } + | SHORT { + $$ = "short"; + } + | INT { + $$ = "int"; + } + ; + +tspecifier: ENUM { + $$ = "enum "; + } + | UNION { + $$ = "union "; + } + | STRUCT { + $$ = "struct "; + } + ; + +stars: '*' stars { stars++; } + | '*' { stars++; } + ; + +sigtype: TOKEN '(' tokenlist ')' { + gtktypes = g_list_prepend(gtktypes,$1); + } + ; + +tokenlist: tokenlist ',' TOKEN { + gtktypes = g_list_append(gtktypes,$3); + } + | TOKEN { + gtktypes = g_list_append(gtktypes,$1); + } + ; + +/*here CCODE will include the ending '}' */ +method: SIGNAL LAST sigtype type TOKEN '(' funcargs ')' onerror '{' CCODE { + if(!has_this) { + yyerror(_("signal without 'this' as " + "first parameter")); + YYERROR; + } + push_function(SIGNAL_LAST_METHOD,NULL, + $5, $9, $11,$1); + } + | SIGNAL LAST sigtype type TOKEN '(' funcargs ')' onerror ';' { + if(!has_this) { + yyerror(_("signal without 'this' as " + "first parameter")); + YYERROR; + } + push_function(SIGNAL_LAST_METHOD, NULL, + $5, $9, NULL,$1); + } + | SIGNAL FIRST sigtype type TOKEN '(' funcargs ')' onerror '{' CCODE { + if(!has_this) { + yyerror(_("signal without 'this' as " + "first parameter")); + YYERROR; + } + push_function(SIGNAL_FIRST_METHOD, NULL, + $5, $9, $11,$1); + } + | SIGNAL FIRST sigtype type TOKEN '(' funcargs ')' onerror ';' { + if(!has_this) { + yyerror(_("signal without 'this' as " + "first parameter")); + YYERROR; + } + push_function(SIGNAL_FIRST_METHOD, NULL, $5, + $9, NULL,$1); + } + | SIGNAL sigtype type TOKEN '(' funcargs ')' onerror '{' CCODE { + if(!has_this) { + yyerror(_("signal without 'this' as " + "first parameter")); + YYERROR; + } + push_function(SIGNAL_LAST_METHOD, NULL, + $4, $8, $10,$1); + } + | SIGNAL sigtype type TOKEN '(' funcargs ')' onerror ';' { + if(!has_this) { + yyerror(_("signal without 'this' as " + "first parameter")); + YYERROR; + } + push_function(SIGNAL_LAST_METHOD, NULL, $4, + $8, NULL,$1); + } + | VIRTUAL type TOKEN '(' funcargs ')' onerror '{' CCODE { + push_function(VIRTUAL_METHOD, NULL, $3, + $7, $9,$1); + } + | VIRTUAL type TOKEN '(' funcargs ')' onerror ';' { + push_function(VIRTUAL_METHOD, NULL, $3, + $7, NULL,$1); + } + | OVERRIDE '(' TYPETOKEN ')' type TOKEN '(' funcargs ')' onerror '{' CCODE { + push_function(OVERRIDE_METHOD, $3, + $6, $10, $12,$1); + } + | PUBLIC type TOKEN '(' funcargs ')' onerror '{' CCODE { + push_function(PUBLIC_SCOPE, NULL, $3, + $7, $9,$1); + } + | PRIVATE type TOKEN '(' funcargs ')' onerror '{' CCODE { + push_function(PRIVATE_SCOPE, NULL, $3, + $7, $9,$1); + } + | TOKEN '(' TOKEN ')' ';' { + if(strcmp($1,"init")==0) { + push_init_arg($3,FALSE); + push_function(INIT_METHOD, NULL, $1, + NULL, NULL,$2); + } else if(strcmp($1,"class_init")==0) { + push_init_arg($3,TRUE); + push_function(CLASS_INIT_METHOD, NULL, + $1, NULL, NULL,$2); + } else { + g_free($1); + g_free($3); + yyerror(_("parse error")); + YYERROR; + } + } + | TOKEN '(' TOKEN ')' '{' CCODE { + if(strcmp($1,"init")==0) { + push_init_arg($3,FALSE); + push_function(INIT_METHOD, NULL, + $1, NULL, $6,$2); + } else if(strcmp($1,"class_init")==0) { + push_init_arg($3,TRUE); + push_function(CLASS_INIT_METHOD, NULL, + $1, NULL, $6,$2); + } else { + g_free($1); + g_free($3); + g_string_free($3,TRUE); + yyerror(_("parse error")); + YYERROR; + } + } + ; + +onerror: ONERROR TOKEN { $$ = $2; } + | ONERROR number { $$ = $2; } + | ONERROR '{' CCODE { + $$ = ($3)->str; + g_string_free($3,FALSE); + } + | '=' '1' { ; } + | { $$ = NULL; } + ; + + + +funcargs: VOID { has_this = FALSE; } + | TOKEN { + has_this = TRUE; + if(strcmp($1,"this")==0) + push_this($1); + else { + g_free($1); + yyerror(_("parse error")); + YYERROR; + } + } + | TOKEN ',' arglist { + has_this = TRUE; + if(strcmp($1,"this")==0) + push_this($1); + else { + g_free($1); + yyerror(_("parse error")); + YYERROR; + } + } + | arglist { has_this = FALSE; } + ; + +arglist: arglist ',' arg { ; } + | arg { ; } + ; + +arg: type TOKEN { + push_funcarg($2); + } + | type TOKEN '(' CHECK checklist ')' { + push_funcarg($2); + } + ; + +checklist: checklist check { ; } + | check { ; } + ; + +check: CNULL { + Node *node = new_check(NULL_CHECK,NULL); + checks = g_list_append(checks,node); + } + | TYPE { + Node *node = new_check(TYPE_CHECK,NULL); + checks = g_list_append(checks,node); + } + | '>' number { + Node *node = new_check(GT_CHECK,$2); + checks = g_list_append(checks,node); + } + | '<' number { + Node *node = new_check(LT_CHECK,$2); + checks = g_list_append(checks,node); + } + | '>' '=' number { + Node *node = new_check(GE_CHECK,$3); + checks = g_list_append(checks,node); + } + | '<' '=' number { + Node *node = new_check(LE_CHECK,$3); + checks = g_list_append(checks,node); + } + | '=' '=' number { + Node *node = new_check(EQ_CHECK,$3); + checks = g_list_append(checks,node); + } + | '!' '=' number { + Node *node = new_check(NE_CHECK,$3); + checks = g_list_append(checks,node); + } + ; + +number: NUMBER { $$ = $1; } + | '-' NUMBER { + $$ = g_strconcat("-",$2,NULL); + g_free($2); + } + ; + +%% diff --git a/src/test.gob b/src/test.gob new file mode 100644 index 0000000..76785d8 --- /dev/null +++ b/src/test.gob @@ -0,0 +1,67 @@ +%{ +#include + +static void jjjj(void); +%} + +%h{ +void bubu(void); +%} + +class Gtk:Weird:Button from Gtk:Button { + public int i; + argument INT i set { this->i = ARG; } get { ARG = this->i; } ; + private int j; + public GtkWidget * h; + + init(object) { + GtkWeirdButton *but = GTK_WEIRD_BUTTON(object); + but->i=0; + } + class_init(class); + public GtkWidget * new(int j (check > 0)) { + GtkWidget *ret; + ret = GTK_WIDGET (GET_NEW); + + GTK_WEIRD_BUTTON(ret)->j = j; + + return ret; + } + private int blah(this, Gtk:Widget * wid (check null type), + int h (check > 0)) onerror -1 { + gtk_container_add(GTK_CONTAINER(this),wid); + return h; + } + signal last INT (POINTER, INT) + int bleh(this, Gtk:Widget * wid (check null type), + int h (check > 0)) { + return blah(this,wid,h); + } + signal first NONE (NONE) + void bloh(this); + virtual void * bah(this, int h (check > 0)) onerror NULL { + beh(this,h); + return NULL; + } + virtual int beh(this, int h (check > 0)); + override(Gtk:Container) void add(Gtk:Container * this (check null type), + Gtk:Widget * wid (check null type)) { + if (GTK_CONTAINER_CLASS (parent_class)->add) + (* GTK_CONTAINER_CLASS (parent_class)->add) (this,wid); + } +} + +%{ + +static void +jjjj(void) +{ +} + +void +bubu(void) +{ + jjjj(); +} + +%} diff --git a/src/tree.c b/src/tree.c new file mode 100644 index 0000000..91e3a23 --- /dev/null +++ b/src/tree.c @@ -0,0 +1,116 @@ +/* GOB C Preprocessor + * Copyright (C) 1999 the Free Software Foundation. + * + * Author: George Lebl + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include +#include "tree.h" + +Node * +new_ccode(int header, GString *cbuf) +{ + CCode *node = (CCode *)g_new(Node,1); + node->type = CCODE_NODE; + node->header = header; + node->cbuf = cbuf; + return (Node *)node; +} + +Node * +new_class(char *otype, char *ptype, GList *nodes) +{ + Class *node = (Class *)g_new(Node,1); + node->type = CLASS_NODE; + node->otype = otype; + node->ptype = ptype; + node->nodes = nodes; + return (Node *)node; +} + +Node * +new_type(int stars, char *name) +{ + Type *node = (Type *)g_new(Node,1); + node->type = TYPE_NODE; + node->stars = stars; + node->name = name; + return (Node *)node; +} + +Node * +new_check(int chtype, char *number) +{ + Check *node = (Check *)g_new(Node,1); + node->type = CHECK_NODE; + node->chtype = chtype; + node->number = number; + return (Node *)node; +} + +Node * +new_funcarg(Type *atype, char *name, GList *checks) +{ + FuncArg *node = (FuncArg *)g_new(Node,1); + node->type = FUNCARG_NODE; + node->atype = atype; + node->name = name; + node->checks = checks; + return (Node *)node; +} + +Node * +new_method(int scope, Type *mtype, char *otype, GList *gtktypes, char *id, GList *args, char *onerror, GString *cbuf, int line_no) +{ + Method *node = (Method *)g_new(Node,1); + node->type = METHOD_NODE; + node->scope = scope; + node->mtype = mtype; + node->otype = otype; + node->gtktypes = gtktypes; + node->id = id; + node->args = args; + node->onerror = onerror; + node->cbuf = cbuf; + node->line_no = line_no; + return (Node *)node; +} + +Node * +new_argument(char *gtktype, GList *flags, char *name, GString *get, GString *set) +{ + Argument *node = (Argument *)g_new(Node,1); + node->type = ARGUMENT_NODE; + node->gtktype = gtktype; + node->flags = flags; + node->name = name; + node->get = get; + node->set = set; + return (Node *)node; +} + +Node * +new_variable(int scope, Type *vtype, char *id) +{ + Variable *node = (Variable *)g_new(Node,1); + node->type = VARIABLE_NODE; + node->scope = scope; + node->vtype = vtype; + node->id = id; + return (Node *)node; +} diff --git a/src/tree.h b/src/tree.h new file mode 100644 index 0000000..d3617a9 --- /dev/null +++ b/src/tree.h @@ -0,0 +1,152 @@ +/* GOB C Preprocessor + * Copyright (C) 1999 the Free Software Foundation. + * + * Author: George Lebl + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef _TREE_H_ +#define _TREE_H_ + +#include + +enum { + CCODE_NODE, + CLASS_NODE, + TYPE_NODE, + CHECK_NODE, + FUNCARG_NODE, + METHOD_NODE, + ARGUMENT_NODE, + VARIABLE_NODE +}; + +typedef union _Node Node; + +typedef struct _CCode CCode; +struct _CCode { + int type; + int header; + GString *cbuf; +}; + +typedef struct _Class Class; +struct _Class { + int type; + char *otype; /*this object class type*/ + char *ptype; /*parent class type*/ + GList *nodes; +}; + +typedef struct _Type Type; +struct _Type { + int type; + int stars; + char *name; +}; + +enum { + NULL_CHECK, + TYPE_CHECK, + LT_CHECK, + GT_CHECK, + LE_CHECK, + GE_CHECK, + EQ_CHECK, + NE_CHECK +}; + +typedef struct _Check Check; +struct _Check { + int type; + int chtype; + char *number; +}; + +typedef struct _FuncArg FuncArg; +struct _FuncArg { + int type; + Type *atype; + char *name; + GList *checks; +}; + +typedef struct _Argument Argument; +struct _Argument { + int type; + char *gtktype; + GList *flags; + char *name; + GString *get; + GString *set; +}; + +/*scope type*/ +enum { + PUBLIC_SCOPE, + PRIVATE_SCOPE, + INIT_METHOD, + CLASS_INIT_METHOD, + VIRTUAL_METHOD, + SIGNAL_LAST_METHOD, + SIGNAL_FIRST_METHOD, + OVERRIDE_METHOD +}; + +typedef struct _Method Method; +struct _Method { + int type; + int scope; + Type *mtype; + char *otype; /*for override methods*/ + GList *gtktypes; /*GTK types for a signal*/ + char *id; + GList *args; + char *onerror; + GString *cbuf; + int line_no; +}; + +typedef struct _Variable Variable; +struct _Variable { + int type; + int scope; + Type *vtype; + char *id; +}; + +union _Node { + int type; + CCode ccode; + Class class; + Type _type; + Check check; + Argument argument; + Method method; + Variable variable; +}; + +Node *new_ccode(int header, GString *cbuf); +Node *new_class(char *otype, char *ptype, GList *nodes); +Node *new_type(int stars, char *name); +Node *new_check(int chtype, char *number); +Node *new_funcarg(Type *atype, char *name, GList *checks); +Node *new_method(int scope, Type *mtype, char *otype, GList *gtktypes, char *id, GList *args, char *onerror, GString *cbuf,int line_no); +Node *new_argument(char *gtktype, GList *flags, char *name, GString *get, GString *set); +Node *new_variable(int scope, Type *vtype, char *id); + +#endif -- 2.43.0