dotgnu-pnet-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[dotgnu-pnet-commits] treecc ChangeLog Makefile.am gen.c gen.h info.h...


From: Rhys Weatherley
Subject: [dotgnu-pnet-commits] treecc ChangeLog Makefile.am gen.c gen.h info.h...
Date: Mon, 04 Jun 2007 10:14:30 +0000

CVSROOT:        /sources/dotgnu-pnet
Module name:    treecc
Changes by:     Rhys Weatherley <rweather>      07/06/04 10:14:30

Modified files:
        .              : ChangeLog Makefile.am gen.c gen.h info.h main.c 
                         options.c stream.c stream.h 
        doc            : treecc.texi 
Added files:
        .              : gen_python.c 

Log message:
        Add Python language binding to treecc.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/treecc/ChangeLog?cvsroot=dotgnu-pnet&r1=1.126&r2=1.127
http://cvs.savannah.gnu.org/viewcvs/treecc/Makefile.am?cvsroot=dotgnu-pnet&r1=1.11&r2=1.12
http://cvs.savannah.gnu.org/viewcvs/treecc/gen.c?cvsroot=dotgnu-pnet&r1=1.4&r2=1.5
http://cvs.savannah.gnu.org/viewcvs/treecc/gen.h?cvsroot=dotgnu-pnet&r1=1.4&r2=1.5
http://cvs.savannah.gnu.org/viewcvs/treecc/info.h?cvsroot=dotgnu-pnet&r1=1.12&r2=1.13
http://cvs.savannah.gnu.org/viewcvs/treecc/main.c?cvsroot=dotgnu-pnet&r1=1.5&r2=1.6
http://cvs.savannah.gnu.org/viewcvs/treecc/options.c?cvsroot=dotgnu-pnet&r1=1.10&r2=1.11
http://cvs.savannah.gnu.org/viewcvs/treecc/stream.c?cvsroot=dotgnu-pnet&r1=1.5&r2=1.6
http://cvs.savannah.gnu.org/viewcvs/treecc/stream.h?cvsroot=dotgnu-pnet&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/treecc/gen_python.c?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/treecc/doc/treecc.texi?cvsroot=dotgnu-pnet&r1=1.18&r2=1.19

Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/dotgnu-pnet/treecc/ChangeLog,v
retrieving revision 1.126
retrieving revision 1.127
diff -u -b -r1.126 -r1.127
--- ChangeLog   3 Jun 2007 06:00:40 -0000       1.126
+++ ChangeLog   4 Jun 2007 10:14:29 -0000       1.127
@@ -1,4 +1,9 @@
 
+2007-06-04  Rhys Weatherley  <address@hidden>
+
+       * Makefile.am, gen.c, gen.h, gen_python.c, info.h, main.c, options.c,
+       stream.c, stream.h, doc/treecc.texi: add Python language binding to 
treecc.
+
 2007-06-03  Rhys Weatherley  <address@hidden>
 
        * tests/test_input.c: fix 32bit-ism that gave a warning on amd64.

Index: Makefile.am
===================================================================
RCS file: /sources/dotgnu-pnet/treecc/Makefile.am,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -b -r1.11 -r1.12
--- Makefile.am 21 Jan 2007 14:45:04 -0000      1.11
+++ Makefile.am 4 Jun 2007 10:14:29 -0000       1.12
@@ -21,6 +21,7 @@
                                          gen_ruby.c \
                                          gen_java.c \
                                          gen_php.c \
+                                         gen_python.c \
                                          info.h \
                                          input.c \
                                          input.h \

Index: gen.c
===================================================================
RCS file: /sources/dotgnu-pnet/treecc/gen.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -b -r1.4 -r1.5
--- gen.c       10 Jan 2003 22:13:37 -0000      1.4
+++ gen.c       4 Jun 2007 10:14:29 -0000       1.5
@@ -1,7 +1,7 @@
 /*
  * gen.c - Generate code to "treecc" output files.
  *
- * Copyright (C) 2001  Southern Storm Software, Pty Ltd.
+ * Copyright (C) 2001, 2007  Southern Storm Software, Pty Ltd.
  *
  * 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
@@ -68,6 +68,11 @@
                }
                break;
 
+               case TREECC_LANG_PYTHON:
+               {
+                       TreeCCGeneratePython(context);
+               }
+               break;
        }
 }
 

Index: gen.h
===================================================================
RCS file: /sources/dotgnu-pnet/treecc/gen.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -b -r1.4 -r1.5
--- gen.h       10 Jan 2003 22:13:37 -0000      1.4
+++ gen.h       4 Jun 2007 10:14:29 -0000       1.5
@@ -1,7 +1,7 @@
 /*
  * gen.h - Generate code to "treecc" output files.
  *
- * Copyright (C) 2001, 2002  Southern Storm Software, Pty Ltd.
+ * Copyright (C) 2001, 2002, 2007  Southern Storm Software, Pty Ltd.
  *
  * 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
@@ -39,6 +39,7 @@
 void TreeCCGenerateCSharp(TreeCCContext *context);
 void TreeCCGenerateRuby(TreeCCContext *context);
 void TreeCCGeneratePHP(TreeCCContext *context);
+void TreeCCGeneratePython(TreeCCContext *context);
 
 /*
  * Control structure for generating the code for

Index: info.h
===================================================================
RCS file: /sources/dotgnu-pnet/treecc/info.h,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -b -r1.12 -r1.13
--- info.h      20 Nov 2003 00:16:09 -0000      1.12
+++ info.h      4 Jun 2007 10:14:30 -0000       1.13
@@ -1,7 +1,7 @@
 /*
  * info.h - Store information about parsed "treecc" input files.
  *
- * Copyright (C) 2001  Southern Storm Software, Pty Ltd.
+ * Copyright (C) 2001, 2007  Southern Storm Software, Pty Ltd.
  *
  * 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
@@ -75,6 +75,7 @@
 #define        TREECC_LANG_CSHARP                      3
 #define        TREECC_LANG_RUBY                        4
 #define        TREECC_LANG_PHP                         5
+#define        TREECC_LANG_PYTHON                      6
 
 /*
  * Information that is stored about a field.

Index: main.c
===================================================================
RCS file: /sources/dotgnu-pnet/treecc/main.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -b -r1.5 -r1.6
--- main.c      29 Jan 2003 00:46:54 -0000      1.5
+++ main.c      4 Jun 2007 10:14:30 -0000       1.6
@@ -1,7 +1,7 @@
 /*
  * main.c - Main program entry point for "treecc".
  *
- * Copyright (C) 2001, 2002  Southern Storm Software, Pty Ltd.
+ * Copyright (C) 2001, 2002, 2007  Southern Storm Software, Pty Ltd.
  *
  * 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
@@ -471,7 +471,7 @@
 static void Usage(char *progname)
 {
        fprintf(stderr, "TREECC " VERSION " - Tree Compiler-Compiler\n");
-       fprintf(stderr, "Copyright (c) 2001, 2002 Southern Storm Software, Pty 
Ltd.\n");
+       fprintf(stderr, "Copyright (c) 2001, 2002, 2007 Southern Storm 
Software, Pty Ltd.\n");
        fprintf(stderr, "\n");
        fprintf(stderr, "Usage: %s [options] input ...\n", progname);
        fprintf(stderr, "\n");

Index: options.c
===================================================================
RCS file: /sources/dotgnu-pnet/treecc/options.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -b -r1.10 -r1.11
--- options.c   20 Nov 2003 00:16:09 -0000      1.10
+++ options.c   4 Jun 2007 10:14:30 -0000       1.11
@@ -1,7 +1,7 @@
 /*
  * options.c - Process options from "treecc" input files.
  *
- * Copyright (C) 2001  Southern Storm Software, Pty Ltd.
+ * Copyright (C) 2001, 2007  Southern Storm Software, Pty Ltd.
  *
  * 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
@@ -259,6 +259,10 @@
                {
                        context->language = TREECC_LANG_PHP;
                }
+               else if(!strcmp(value, "python") || !strcmp(value, "Python"))
+               {
+                       context->language = TREECC_LANG_PYTHON;
+               }
                else
                {
                        return TREECC_OPT_INVALID_VALUE;

Index: stream.c
===================================================================
RCS file: /sources/dotgnu-pnet/treecc/stream.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -b -r1.5 -r1.6
--- stream.c    27 Jan 2003 00:25:25 -0000      1.5
+++ stream.c    4 Jun 2007 10:14:30 -0000       1.6
@@ -1,7 +1,7 @@
 /*
  * stream.c - Stream handling for writing source code.
  *
- * Copyright (C) 2001  Southern Storm Software, Pty Ltd.
+ * Copyright (C) 2001, 2007  Southern Storm Software, Pty Ltd.
  *
  * 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
@@ -523,6 +523,92 @@
        }
 }
 
+void TreeCCStreamCodeIndentPython(TreeCCStream *stream, char *code, int indent)
+{
+       int temp;
+       int startline = 1;
+       int spaces = -1;
+       int len;
+
+       /* Strip off the first and last blank lines, as they are probably
+          due to formatting in the treecc file, and not part of the actual
+          Python code that we need to output */
+       temp = 0;
+       while(code[temp] != '\0' && code[temp] != '\n')
+       {
+               if(code[temp] != ' ' && code[temp] != '\t')
+                       break;
+               ++temp;
+       }
+       if(code[temp] == '\n')
+       {
+               code += temp + 1;
+       }
+       len = strlen(code);
+       if(len > 0)
+       {
+               --len;
+               while(len > 0 && (code[len - 1] == ' ' || code[len - 1] == 
'\t'))
+                       --len;
+               if(len > 0 && code[len - 1] != '\n')
+               {
+                       /* Last line is not completely blank */
+                       len = strlen(code);
+               }
+       }
+
+       /* Bail out if no code to output at all */
+       if(!len)
+               return;
+
+       /* Output the remaining code */
+       while(len > 0)
+       {
+               if(*code == '\n')
+               {
+                       StreamPut(*code, stream);
+                       ++(stream->linenum);
+                       startline = 1;
+                       ++code;
+                       --len;
+               }
+               else if(startline)
+               {
+                       /* Expand white space at the start of a line */
+                       spaces = 0;
+                       while(len > 0 && (*code == ' ' || *code == '\t'))
+                       {
+                               if(*code++ == ' ')
+                                       ++spaces;
+                               else
+                                       spaces = (spaces + 8) & ~7;
+                               --len;
+                       }
+                       startline = 0;
+               }
+               else
+               {
+                       if(spaces >= 0)
+                       {
+                               temp = indent * 4 + spaces;
+                               while(temp-- > 0)
+                               {
+                                       StreamPut(' ', stream);
+                               }
+                               spaces = -1;
+                       }
+                       StreamPut(*code, stream);
+                       ++code;
+                       --len;
+                       startline = 0;
+               }
+       }
+       if(!startline)
+       {
+               /* Make sure that the last line is terminated */
+               StreamPut('\n', stream);
+       }
+}
 
 void TreeCCStreamFixLine(TreeCCStream *stream)
 {
@@ -647,6 +733,13 @@
        OutputDefns(stream, 0);
 }
 
+void TreeCCStreamSourceTopSpecial(TreeCCStream *stream, int ch)
+{
+       TreeCCStreamPrint(stream, "%c %s.  Generated automatically by treecc\n",
+                                         ch, stream->embedName);
+       OutputDefns(stream, 0);
+}
+
 void TreeCCStreamSourceTopCS(TreeCCStream *stream)
 {
        OutputDefns(stream, 0);

Index: stream.h
===================================================================
RCS file: /sources/dotgnu-pnet/treecc/stream.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- stream.h    9 Nov 2002 11:36:26 -0000       1.3
+++ stream.h    4 Jun 2007 10:14:30 -0000       1.4
@@ -1,7 +1,7 @@
 /*
  * stream.h - Stream handling for writing source code.
  *
- * Copyright (C) 2001  Southern Storm Software, Pty Ltd.
+ * Copyright (C) 2001, 2007  Southern Storm Software, Pty Ltd.
  *
  * 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
@@ -154,6 +154,14 @@
                                                                 char 
indentchar, int indent);
 
 /*
+ * Output a block of literal code to a stream which is indented.
+ * The code is normalized to remove leading TAB's and replace
+ * them with spaces, as per Python's conventions.  Each indent
+ * level corresponds to four spaces.
+ */
+void TreeCCStreamCodeIndentPython(TreeCCStream *stream, char *code, int 
indent);
+
+/*
  * Fix the line number information in the output stream
  * after outputting a block of code.
  */
@@ -187,6 +195,12 @@
 void TreeCCStreamSourceTopCS(TreeCCStream *stream);
 
 /*
+ * Output extra information that is needed at the top of a source file,
+ * using a special comment character.
+ */
+void TreeCCStreamSourceTopSpecial(TreeCCStream *stream, int ch);
+
+/*
  * Output extra information that is needed at the bottom of a source file.
  */
 void TreeCCStreamSourceBottom(TreeCCStream *stream);

Index: doc/treecc.texi
===================================================================
RCS file: /sources/dotgnu-pnet/treecc/doc/treecc.texi,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -b -r1.18 -r1.19
--- doc/treecc.texi     11 Mar 2004 00:12:53 -0000      1.18
+++ doc/treecc.texi     4 Jun 2007 10:14:30 -0000       1.19
@@ -1120,7 +1120,8 @@
 @item %option lang = LANGUAGE
 @cindex lang option
 Specify the output language.  Must be one of @code{"C"}, @code{"C++"},
address@hidden"Java"}, or @code{"C#"}.  The default is @code{"C"}.
address@hidden"Java"}, @code{"C#"}, @code{"Ruby"}, @code{"PHP"}, or 
@code{"Python"}.
+The default is @code{"C"}.
 
 @item %option block_size = NUM
 @cindex block_size option
@@ -1351,6 +1352,7 @@
 * Java Language::  Java Language API's
 * C# Language::    C# Language API's
 * Ruby Language::  Ruby Language API's
+* Python Language::  Python Language API's
 @end menu
 
 @c -----------------------------------------------------------------------
@@ -2405,7 +2407,7 @@
 
 @c -----------------------------------------------------------------------
 
address@hidden Ruby Language, Full Expression Example, C# Language, Output APIs
address@hidden Ruby Language, Python Language, C# Language, Output APIs
 @section Ruby Language APIs
 @cindex Ruby APIs
 
@@ -2682,7 +2684,145 @@
 
 @c -----------------------------------------------------------------------
 
address@hidden Full Expression Example, EBNF Syntax, Ruby Language, Top
address@hidden Python Language, Full Expression Example, Ruby Language, Output 
APIs
address@hidden Python Language APIs
address@hidden Python APIs
+
+In the Python output language, each node type is converted into a
address@hidden that contains the node's fields, operations, and other
+house-keeping definitions.  The following example demonstrates how
+treecc node declarations are converted into Python source code:
+
address@hidden
+%node expression %abstract %typedef =
address@hidden
+    %nocreate type_code type;
address@hidden
+%node binary expression %abstract =
address@hidden
+    expression expr1;
+    expression expr2;
address@hidden
+%node plus binary
address@hidden example
+
+becomes:
+
address@hidden
+class expression:
+    KIND = 1
+    def __init__(self):
+        self.kind = 1
+        self.filename = yycurrfilename()
+        self.linenum = yycurrlinenum()
+
+    def getKindName(self):
+        return self.__class__.__name__
+
+class binary (expression):
+    KIND = 2
+    def __init__(self, expr1, expr2):
+        expression.__init__(self)
+        self.kind = 2
+        self.expr1 = expr1
+        self.expr2 = expr2
+
+class plus (binary):
+    KIND = 3
+    def __init__(self, expr1, expr2):
+        binary.__init__(self, expr1, expr2)
+        self.kind = 3
address@hidden example
+
+The following standard members are available on every node type:
+
address@hidden @code
address@hidden KIND
address@hidden KIND field (Python)
+The kind value for the node type corresponding to this class.
+The kind value for node type @samp{NAME} is called @samp{NAME.KIND}.
+
address@hidden kind
address@hidden kind field (Python)
+Gets the numeric kind value associated with a particular node.
+The kind value for node type @samp{NAME} is called @samp{NAME.KIND}.
+
address@hidden getKindName()
address@hidden getKindName method (Python)
+The name of the node kind associated with a particular node.  This may
+be helpful for debugging and logging code.
+
address@hidden filename
address@hidden filename field (Python)
+The filename corresponding to where the node was created during parsing.
+This field is only initialized if @samp{%option track_lines} was
+specified.
+
address@hidden linenum
address@hidden linenum field (Python)
+The line number corresponding to where the node was created during
+parsing.  This field is only initialized if @samp{%option track_lines}
+was specified.
address@hidden table
+
+The @code{isA()} method from the other output languages is not present
+in the Python binding.  Use the standard Python @code{isinstance}
+function instead.
+
+Enumerated types are converted into a Python @samp{class} definition:
+
address@hidden
+%enum JavaType =
address@hidden
+    JT_BYTE,
+    JT_SHORT,
+    JT_CHAR,
+    JT_INT,
+    JT_LONG,
+    JT_FLOAT,
+    JT_DOUBLE,
+    JT_OBJECT_REF
address@hidden
address@hidden example
+
+becomes:
+
address@hidden
+class JavaType:
+    JT_BYTE = 0
+    JT_SHORT = 1
+    JT_CHAR = 2
+    JT_INT = 3
+    JT_LONG = 4
+    JT_FLOAT = 5
+    JT_DOUBLE = 6
+    JT_OBJECT_REF = 7
address@hidden example
+
+Virtual operations are converted into public methods on the Python
+node classes.  Non-virtual operations are converted into a global
+method within the generated Python module.
+
+If @samp{%option track_lines} is specified, then the generated Python
+module is assumed to contain the following global methods to provide line
+tracking information:
+
address@hidden @code
address@hidden yycurrfilename()
address@hidden yycurrfilename method (Python)
+The name of the current input file from the parser.
+
address@hidden yycurrlinenum()
address@hidden yycurrlinenum method (Ruby)
+The number of the current input line from the parser.
address@hidden table
+
+The programmer will typically provide a literal @code{%end} block to
+define these methods.
+
address@hidden 
-----------------------------------------------------------------------
+
address@hidden Full Expression Example, EBNF Syntax, Python Language, Top
 @appendix Full expression example code
 @cindex Full expression example
 

Index: gen_python.c
===================================================================
RCS file: gen_python.c
diff -N gen_python.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gen_python.c        4 Jun 2007 10:14:29 -0000       1.1
@@ -0,0 +1,776 @@
+/*
+ * gen_python.c - Generate Python source code from "treecc" input files.
+ *
+ * Copyright (C) 2007  Southern Storm Software, Pty Ltd.
+ *
+ * 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 "system.h"
+#include "input.h"
+#include "info.h"
+#include "gen.h"
+#include "errors.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Declare the type definitions for a node type.
+ */
+static void DeclareTypeDefs(TreeCCContext *context,
+                                                   TreeCCNode *node)
+{
+       if((node->flags & TREECC_NODE_ENUM) != 0)
+       {
+               /* Define an enumerated type */
+               TreeCCStream *stream = node->source;
+               TreeCCNode *child;
+               int value = 0;
+               int neednl = 0;
+               TreeCCStreamPrint(stream, "class %s:\n", node->name);
+               child = node->firstChild;
+               while(child != 0)
+               {
+                       if((child->flags & TREECC_NODE_ENUM_VALUE) != 0)
+                       {
+                               TreeCCStreamPrint(stream, "    %s = %d\n", 
child->name, value++);
+                               neednl = 1;
+                       }
+                       child = child->nextSibling;
+               }
+               if(neednl)
+               {
+                       TreeCCStreamPrint(stream, "\n");
+               }
+       }
+}
+
+/*
+ * Output the parameters for a node creation function.
+ */
+static int CreateParams(TreeCCContext *context, TreeCCStream *stream,
+                                               TreeCCNode *node, int needComma)
+{
+       TreeCCField *field;
+       if(node->parent)
+       {
+               needComma = CreateParams(context, stream, node->parent, 
needComma);
+       }
+       field = node->fields;
+       while(field != 0)
+       {
+               if((field->flags & TREECC_FIELD_NOCREATE) == 0)
+               {
+                       if(needComma)
+                       {
+                               TreeCCStreamPrint(stream, ", ");
+                       }
+                       TreeCCStreamPrint(stream, "%s", field->name);
+                       needComma = 1;
+               }
+               field = field->next;
+       }
+       return needComma;
+}
+
+/*
+ * Output the parameters to call an inherited constructor.
+ */
+static int InheritParamsSource(TreeCCContext *context, TreeCCStream *stream,
+                                                          TreeCCNode *node, 
int needComma)
+{
+       TreeCCField *field;
+       if(node->parent)
+       {
+               needComma = InheritParamsSource(context, stream,
+                                                                           
node->parent, needComma);
+       }
+       field = node->fields;
+       while(field != 0)
+       {
+               if((field->flags & TREECC_FIELD_NOCREATE) == 0)
+               {
+                       if(needComma)
+                       {
+                               TreeCCStreamPrint(stream, ", ");
+                       }
+                       TreeCCStreamPrint(stream, "%s", field->name);
+                       needComma = 1;
+               }
+               field = field->next;
+       }
+       return needComma;
+}
+
+/*
+ * Implement the virtual methods that have implementations in a node type.
+ */
+static void ImplementVirtuals(TreeCCContext *context, TreeCCStream *stream,
+                                                         TreeCCNode *node, 
TreeCCNode *actualNode)
+{
+       TreeCCVirtual *virt;
+       TreeCCParam *param;
+       TreeCCOperationCase *operCase;
+       int declareCase, abstractCase;
+       TreeCCNode *tempNode;
+       int num, first;
+       int needComma;
+       if(node->parent)
+       {
+               ImplementVirtuals(context, stream, node->parent, actualNode);
+       }
+       virt = node->virtuals;
+       while(virt != 0)
+       {
+               /* Determine if we need a definition for this virtual,
+                  and whether the definition is real or abstract */
+               operCase = TreeCCOperationFindCase(context, actualNode, 
virt->name);
+               if(!operCase)
+               {
+                       tempNode = actualNode->parent;
+                       abstractCase = 1;
+                       while(tempNode != 0)
+                       {
+                               operCase = TreeCCOperationFindCase
+                                                               (context, 
tempNode, virt->name);
+                               if(operCase != 0)
+                               {
+                                       abstractCase = 0;
+                                       break;
+                               }
+                               tempNode = tempNode->parent;
+                       }
+                       declareCase = abstractCase;
+               }
+               else
+               {
+                       declareCase = 1;
+                       abstractCase = 0;
+               }
+               if(declareCase)
+               {
+                       if(abstractCase)
+                       {
+                               if(node == actualNode)
+                               {
+                                       TreeCCStreamPrint(stream, "    def 
%s(", virt->name);
+                               }
+                               else
+                               {
+                                       /* Inherit the "abstract" definition 
from the parent */
+                                       virt = virt->next;
+                                       continue;
+                               }
+                       }
+                       else
+                       {
+                               TreeCCStreamPrint(stream, "    def %s(", 
virt->name);
+                       }
+                       param = virt->oper->params;
+                       needComma = 0;
+                       num = 1;
+                       first = 1;
+                       while(param != 0)
+                       {
+                               if(needComma)
+                               {
+                                       TreeCCStreamPrint(stream, ", ");
+                               }
+                               if(param->name)
+                               {
+                                       TreeCCStreamPrint(stream, "%s", 
param->name);
+                               }
+                               else
+                               {
+                                       TreeCCStreamPrint(stream, "P%d__", num);
+                                       ++num;
+                               }
+                               needComma = 1;
+                               param = param->next;
+                       }
+                       if(!abstractCase)
+                       {
+                               TreeCCStreamPrint(stream, "):\n");
+                               TreeCCStreamCodeIndentPython(stream, 
operCase->code, 1);
+                               TreeCCStreamPrint(stream, "\n");
+                       }
+                       else
+                       {
+                               /* This is an abstract method definition.  
Raise an error */
+                               TreeCCStreamPrint(stream, "):\n");
+                               TreeCCStreamPrint(stream, "        raise 
NotImplementedError\n\n");
+                       }
+               }
+               virt = virt->next;
+       }
+}
+
+/*
+ * Build the type declarations for a node type.
+ */
+static void BuildTypeDecls(TreeCCContext *context,
+                                                  TreeCCNode *node)
+{
+       TreeCCStream *stream;
+       int needComma;
+       TreeCCField *field;
+
+       /* Ignore if this is an enumerated type node */
+       if((node->flags & (TREECC_NODE_ENUM | TREECC_NODE_ENUM_VALUE)) != 0)
+       {
+               return;
+       }
+
+       /* Output the class header */
+       stream = node->source;
+       if(node->parent)
+       {
+               /* Inherit from a specified parent type */
+               TreeCCStreamPrint(stream, "class %s (%s):\n",
+                                                 node->name, 
node->parent->name);
+       }
+       else
+       {
+               /* This type is the base of a class hierarchy */
+               if(context->baseType)
+               {
+                       TreeCCStreamPrint(stream, "class %s (%s):\n",
+                                                         node->name, 
context->baseType);
+               }
+               else
+               {
+                       TreeCCStreamPrint(stream, "class %s:\n", node->name);
+               }
+       }
+
+       /* Declare the kind value */
+       TreeCCStreamPrint(stream, "    KIND = %d\n", node->number);
+
+       /* Declare the constructor for the node type */
+       TreeCCStreamPrint(stream, "    def __init__(self");
+       needComma = 1;
+       CreateParams(context, stream, node, needComma);
+       TreeCCStreamPrint(stream, "):\n");
+
+       /* Call the parent class constructor */
+       if(node->parent)
+       {
+               TreeCCStreamPrint(stream, "        %s.__init__(self", 
node->parent->name);
+               needComma = 1;
+               InheritParamsSource(context, stream, node->parent, needComma);
+               TreeCCStreamPrint(stream, ")\n");
+       }
+
+       /* Set the node kind */
+       TreeCCStreamPrint(stream, "        self.kind = %d\n", node->number);
+
+       /* Track the filename and line number if necessary */
+       if(context->track_lines && !(node->parent))
+       {
+               TreeCCStreamPrint(stream, "        self.filename = 
%scurrfilename()\n",
+                                                 context->yy_replacement);
+               TreeCCStreamPrint(stream, "        self.linenum = 
%scurrlinenum()\n",
+                                                 context->yy_replacement);
+       }
+
+       /* Initialize the fields that are specific to this node type */
+       field = node->fields;
+       while(field != 0)
+       {
+               if((field->flags & TREECC_FIELD_NOCREATE) == 0)
+               {
+                       TreeCCStreamPrint(stream, "        self.%s = %s\n",
+                                                         field->name, 
field->name);
+               }
+               else if(field->value)
+               {
+                       TreeCCStreamPrint(stream, "        self.%s = %s\n",
+                                                         field->name, 
field->value);
+               }
+               field = field->next;
+       }
+       TreeCCStreamPrint(stream, "\n");
+
+       /* Implement the virtual functions */
+       ImplementVirtuals(context, stream, node, node);
+
+       /* If this is a base class, then define the "getKindName" method,
+          which returns the name of the node type */
+       if(!node->parent)
+       {
+               TreeCCStreamPrint(stream, "    def getKindName(self):\n");
+               TreeCCStreamPrint(stream, "        return 
self.__class__.__name__\n");
+               TreeCCStreamPrint(stream, "\n");
+       }
+}
+
+/*
+ * Output spaces for a specific level of indenting.  We use four
+ * spaces for each level of indenting.
+ */
+static void Indent(TreeCCStream *stream, int indent)
+{
+       while(indent > 0)
+       {
+               TreeCCStreamPrint(stream, "    ");
+               --indent;
+       }
+}
+
+/*
+ * Generate the start declarations for a non-virtual operation.
+ */
+static void PythonGenStart(TreeCCContext *context, TreeCCStream *stream,
+                                                  TreeCCOperation *oper)
+{
+       /* Nothing to do here for Python */
+}
+
+/*
+ * Generate the entry point for a non-virtual operation.
+ */
+static void GenEntry(TreeCCContext *context, TreeCCStream *stream,
+                                        TreeCCOperation *oper, int number)
+{
+       TreeCCParam *param;
+       int num;
+       int needComma;
+       if(number != -1)
+       {
+               TreeCCStreamPrint(stream, "def %s_split_%d__(", oper->name, 
number);
+       }
+       else
+       {
+               TreeCCStreamPrint(stream, "def %s(", oper->name);
+       }
+       param = oper->params;
+       num = 1;
+       needComma = 0;
+       while(param != 0)
+       {
+               if(needComma)
+               {
+                       TreeCCStreamPrint(stream, ", ");
+               }
+               if(param->name)
+               {
+                       TreeCCStreamPrint(stream, "%s", param->name);
+               }
+               else
+               {
+                       TreeCCStreamPrint(stream, "P%d__", num);
+                       ++num;
+               }
+               needComma = 1;
+               param = param->next;
+       }
+       TreeCCStreamPrint(stream, "):\n");
+}
+
+/*
+ * Generate the entry point for a non-virtual operation.
+ */
+static void PythonGenEntry(TreeCCContext *context, TreeCCStream *stream,
+                                                  TreeCCOperation *oper)
+{
+       GenEntry(context, stream, oper, -1);
+}
+
+/*
+ * Generate the entry point for a split-out function.
+ */
+static void PythonGenSplitEntry(TreeCCContext *context, TreeCCStream *stream,
+                                                   TreeCCOperation *oper, int 
number)
+{
+       GenEntry(context, stream, oper, number);
+}
+
+/*
+ * Stack of switch contexts.  Python doesn't have a "swtich" statement,
+ * so we need to emulate it using nested "if" statements.  The following
+ * stack allows us to keep track of whether we need an "if" or an "elif",
+ * as well as the name of the parameter to match against.
+ */
+typedef struct
+{
+       char   *paramName;
+       int             nextIsIf;
+       int             needsOr;
+
+} SwitchInfo;
+#define        MaxSwitchDepth          100
+static SwitchInfo switchStack[MaxSwitchDepth];
+static int switchStackSize = 0;
+
+/*
+ * Generate the head of a "switch" statement.
+ */
+static void PythonGenSwitchHead(TreeCCContext *context, TreeCCStream *stream,
+                                                               char 
*paramName, int level, int isEnum)
+{
+       if(switchStackSize >= MaxSwitchDepth)
+       {
+               TreeCCAbort(0, "maximum python switch depth reached");
+               return;
+       }
+       switchStack[switchStackSize].paramName = paramName;
+       switchStack[switchStackSize].nextIsIf = 1;
+       switchStack[switchStackSize].needsOr = 0;
+       ++switchStackSize;
+}
+
+/*
+ * Generate a selector for a "switch" case.
+ */
+static void PythonGenSelector(TreeCCContext *context, TreeCCStream *stream,
+                                                 TreeCCNode *node, int level)
+{
+       SwitchInfo *info = &(switchStack[switchStackSize - 1]);
+       if(info->needsOr)
+       {
+               /* Generating multiple selectors for the same case */
+               TreeCCStreamPrint(stream, " or ");
+       }
+       else if(info->nextIsIf)
+       {
+               Indent(stream, level + 1);
+               TreeCCStreamPrint(stream, "if ");
+               info->nextIsIf = 0;
+       }
+       else
+       {
+               Indent(stream, level + 1);
+               TreeCCStreamPrint(stream, "elif ");
+       }
+       if((node->flags & TREECC_NODE_ENUM_VALUE) != 0)
+       {
+               TreeCCStreamPrint(stream, "%s == %s.%s",
+                                                 info->paramName, 
node->parent->name, node->name);
+       }
+       else if((node->flags & TREECC_NODE_ENUM) == 0)
+       {
+               /* Use the actual node number to prevent unnecessary symbol
+                  lookups at runtime when matching node kinds */
+               TreeCCStreamPrint(stream, "%s.kind == %d",
+                                                 info->paramName, 
node->number);
+       }
+       info->needsOr = 1;
+}
+
+/*
+ * Terminate the selectors and begin the body of a "switch" case.
+ */
+static void PythonGenEndSelectors(TreeCCContext *context, TreeCCStream *stream,
+                                                         int level)
+{
+       SwitchInfo *info = &(switchStack[switchStackSize - 1]);
+       TreeCCStreamPrint(stream, ":\n");
+       info->needsOr = 0;
+}
+
+/*
+ * Generate the code for a case within a function.
+ */
+static void PythonGenCaseFunc(TreeCCContext *context, TreeCCStream *stream,
+                                                         TreeCCOperationCase 
*operCase, int number)
+{
+       TreeCCParam *param;
+       TreeCCTrigger *trigger;
+       int num;
+       int needComma;
+
+       /* Output the header for the function */
+       TreeCCStreamPrint(stream, "def %s_%d__(",
+                                         operCase->oper->name, number);
+       param = operCase->oper->params;
+       trigger = operCase->triggers;
+       num = 1;
+       needComma = 0;
+       while(param != 0)
+       {
+               if(needComma)
+               {
+                       TreeCCStreamPrint(stream, ", ");
+               }
+               if(param->name)
+               {
+                       TreeCCStreamPrint(stream, "%s", param->name);
+               }
+               else
+               {
+                       TreeCCStreamPrint(stream, "P%d__", num);
+                       ++num;
+               }
+               needComma = 1;
+               param = param->next;
+       }
+       if(!needComma)
+       {
+               TreeCCStreamPrint(stream, "void");
+       }
+       TreeCCStreamPrint(stream, "):\n");
+
+       /* Output the code for the operation case */
+       if(operCase->code)
+       {
+               TreeCCStreamCodeIndentPython(stream, operCase->code, 0);
+       }
+       TreeCCStreamPrint(stream, "\n");
+}
+
+/*
+ * Generate a call to a case function from within the "switch".
+ */
+static void PythonGenCaseCall(TreeCCContext *context, TreeCCStream *stream,
+                                                         TreeCCOperationCase 
*operCase, int number,
+                                                         int level)
+{
+       TreeCCParam *param;
+       int num;
+       int needComma;
+
+       /* Indent to the correct level */
+       Indent(stream, level + 2);
+
+       /* Add "return" to the front if the operation is non-void */
+       if(strcmp(operCase->oper->returnType, "void") != 0)
+       {
+               TreeCCStreamPrint(stream, "return ");
+       }
+
+       /* Print out the call */
+       TreeCCStreamPrint(stream, "%s_%d__(", operCase->oper->name, number);
+       param = operCase->oper->params;
+       num = 1;
+       needComma = 0;
+       while(param != 0)
+       {
+               if(needComma)
+               {
+                       TreeCCStreamPrint(stream, ", ");
+               }
+               if(param->name)
+               {
+                       TreeCCStreamPrint(stream, "%s", param->name);
+               }
+               else
+               {
+                       TreeCCStreamPrint(stream, "P%d__", num);
+                       ++num;
+               }
+               needComma = 1;
+               param = param->next;
+       }
+       TreeCCStreamPrint(stream, ")\n");
+}
+
+/*
+ * Generate the code for a case inline within the "switch".
+ */
+static void PythonGenCaseInline(TreeCCContext *context, TreeCCStream *stream,
+                                                               
TreeCCOperationCase *operCase, int level)
+{
+       if(operCase->code)
+       {
+               TreeCCStreamCodeIndentPython(stream, operCase->code, level + 1);
+       }
+       else
+       {
+               /* No code for this case, so just output a "pass" instruction */
+               Indent(stream, level + 2);
+               TreeCCStreamPrint(stream, "pass\n");
+       }
+}
+
+/*
+ * Generate the code for a call to a split function within the "switch".
+ */
+static void PythonGenCaseSplit(TreeCCContext *context, TreeCCStream *stream,
+                                                          TreeCCOperationCase 
*operCase, int number,
+                                                          int level)
+{
+       TreeCCParam *param;
+       int num;
+       int needComma;
+
+       /* Indent to the correct level */
+       Indent(stream, level + 2);
+
+       /* Add "return" to the front if the operation is non-void */
+       if(strcmp(operCase->oper->returnType, "void") != 0)
+       {
+               TreeCCStreamPrint(stream, "return ");
+       }
+
+       /* Print out the call */
+       TreeCCStreamPrint(stream, "%s_split_%d__(", operCase->oper->name, 
number);
+       param = operCase->oper->params;
+       num = 1;
+       needComma = 0;
+       while(param != 0)
+       {
+               if(needComma)
+               {
+                       TreeCCStreamPrint(stream, ", ");
+               }
+               if(param->name)
+               {
+                       TreeCCStreamPrint(stream, "%s", param->name);
+               }
+               else
+               {
+                       TreeCCStreamPrint(stream, "P%d__", num);
+                       ++num;
+               }
+               needComma = 1;
+               param = param->next;
+       }
+       TreeCCStreamPrint(stream, ")\n");
+}
+
+/*
+ * Terminate a "switch" case.
+ */
+static void PythonGenEndCase(TreeCCContext *context, TreeCCStream *stream,
+                                                        int level)
+{
+       /* Nohing to do here for Python */
+}
+
+/*
+ * Terminate the "switch" statement.
+ */
+static void PythonGenEndSwitch(TreeCCContext *context, TreeCCStream *stream,
+                                                          int level)
+{
+       --switchStackSize;
+}
+
+/*
+ * Generate the exit point for a non-virtual operation.
+ */
+static void PythonGenExit(TreeCCContext *context, TreeCCStream *stream,
+                                                 TreeCCOperation *oper)
+{
+       if(strcmp(oper->returnType, "void") != 0)
+       {
+               /* Generate a default return value for the function */
+               if(oper->defValue)
+               {
+                       TreeCCStreamPrint(stream, "    return %s\n", 
oper->defValue);
+               }
+               else
+               {
+                       TreeCCStreamPrint(stream, "    return None\n");
+               }
+       }
+       TreeCCStreamPrint(stream, "\n");
+}
+
+/*
+ * Generate the end declarations for a non-virtual operation.
+ */
+static void PythonGenEnd(TreeCCContext *context, TreeCCStream *stream,
+                                                 TreeCCOperation *oper)
+{
+       /* Nothing to do here for Python */
+}
+
+/*
+ * Table of non-virtual code generation functions.
+ */
+static TreeCCNonVirtual const TreeCCNonVirtualFuncsPython = {
+       PythonGenStart,
+       PythonGenEntry,
+       PythonGenSplitEntry,
+       PythonGenSwitchHead,
+       PythonGenSelector,
+       PythonGenEndSelectors,
+       PythonGenCaseFunc,
+       PythonGenCaseCall,
+       PythonGenCaseInline,
+       PythonGenCaseSplit,
+       PythonGenEndCase,
+       PythonGenEndSwitch,
+       PythonGenExit,
+       PythonGenEnd
+};
+
+/*
+ * Write out header information for all streams.
+ */
+static void WritePythonHeaders(TreeCCContext *context)
+{
+       TreeCCStream *stream = context->streamList;
+       while(stream != 0)
+       {
+               if(!(stream->isHeader))
+               {
+                       TreeCCStreamSourceTopSpecial(stream, '#');
+               }
+               if(stream->defaultFile)
+               {
+                       /* Reset the dirty flag if this is a default stream,
+                          because we don't want to write out the final file
+                          if it isn't actually written to in practice */
+                       stream->dirty = 0;
+               }
+               stream = stream->nextStream;
+       }
+}
+
+/*
+ * Write out footer information for all streams.
+ */
+static void WritePythonFooters(TreeCCContext *context)
+{
+       TreeCCStream *stream = context->streamList;
+       while(stream != 0)
+       {
+               if(stream->defaultFile && !(stream->dirty))
+               {
+                       /* Clear the default file's contents, which we don't 
need */
+                       TreeCCStreamClear(stream);
+               }
+               else if(!(stream->isHeader))
+               {
+                       TreeCCStreamSourceBottom(stream);
+               }
+               stream = stream->nextStream;
+       }
+}
+
+void TreeCCGeneratePython(TreeCCContext *context)
+{
+       /* Don't ever print line numbers for Python */
+       context->print_lines = 0;
+
+       /* Write all stream headers */
+       WritePythonHeaders(context);
+
+       /* Generate the contents of the source stream */
+       TreeCCNodeVisitAll(context, DeclareTypeDefs);
+       TreeCCNodeVisitAll(context, BuildTypeDecls);
+       TreeCCGenerateNonVirtuals(context, &TreeCCNonVirtualFuncsPython);
+
+       /* Write all stream footers */
+       WritePythonFooters(context);
+}
+
+#ifdef __cplusplus
+};
+#endif




reply via email to

[Prev in Thread] Current Thread [Next in Thread]