[Top][All Lists]
[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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [dotgnu-pnet-commits] treecc ChangeLog Makefile.am gen.c gen.h info.h...,
Rhys Weatherley <=