[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Dotgnu-pnet-commits] CVS: pnetlib/System/CodeDom gencdom.c,NONE,1.1 rul
From: |
Rhys Weatherley <address@hidden> |
Subject: |
[Dotgnu-pnet-commits] CVS: pnetlib/System/CodeDom gencdom.c,NONE,1.1 rules.txt,NONE,1.1 |
Date: |
Thu, 07 Nov 2002 23:07:43 -0500 |
Update of /cvsroot/dotgnu-pnet/pnetlib/System/CodeDom
In directory subversions:/tmp/cvs-serv10930/System/CodeDom
Added Files:
gencdom.c rules.txt
Log Message:
Add a rule-based code generator for autogenerating CodeDom classes.
--- NEW FILE ---
/*
* gencdom.c - Generate System.CodeDom classes from rules.txt.
*
* Copyright (C) 2002 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 <stdio.h>
#include <string.h>
/*
* Forward declarations.
*/
static void processInput(FILE *stream, FILE *outstream);
static int parseRule(char *line);
static void generateCode(FILE *stream);
static void generateHeader(FILE *stream);
static void generateFooter(FILE *stream);
int main(int argc, char *argv[])
{
generateHeader(stdout);
processInput(stdin, stdout);
generateFooter(stdout);
return 0;
}
/*
* Read a single line from an input stream and handle continuations.
*/
static int readLine(char *buffer, FILE *stream)
{
int left = BUFSIZ;
int len;
while(fgets(buffer, left, stream))
{
len = strlen(buffer);
while(len > 0 && (buffer[len - 1] == '\n' || buffer[len - 1] ==
'\r'))
{
--len;
}
buffer[len] = '\0';
if(len > 0 && buffer[len - 1] == ':')
{
buffer += len;
left -= len;
}
else if(len > 0 && buffer[len - 1] == '\\')
{
--len;
buffer[len] = '\0';
buffer += len;
left -= len;
}
else
{
return 1;
}
}
return 0;
}
/*
* Process input from a stream.
*/
static void processInput(FILE *stream, FILE *outstream)
{
char buffer[BUFSIZ];
while(readLine(buffer, stream))
{
if(parseRule(buffer))
{
generateCode(outstream);
}
}
}
/*
* Determine if a string ends in a specific tail.
*/
static int endsIn(const char *str1, const char *str2)
{
int len1 = strlen(str1);
int len2 = strlen(str2);
if(len1 > len2 && !strncmp(str1 + len1 - len2, str2, len2))
{
return 1;
}
else
{
return 0;
}
}
/*
* Parsed contents of a rule.
*/
static char *name;
static char *parent;
static char *contentType[16];
static char *contentName[16];
static int contentIsParams[16];
static int contentIsOptional[16];
static int specialConstructors;
static int numContents;
/*
* Parse a rule line from an input stream. Rules look like this:
*
* CodeBinaryOperatorExpression:
* CodeExpression<Left> CodeBinaryOperatorType<Operator> \
* CodeExpression<Right>
*/
static int parseRule(char *line)
{
int implicit;
char *contents;
/* Clear the rule information */
name = "";
parent = "";
numContents = 0;
specialConstructors = 1;
/* Skip leading white space */
while(*line != '\0' && (*line == ' ' || *line == '\t' ||
*line == '\r' || *line
== '\n'))
{
++line;
}
if(*line == '\0' || *line == '#')
{
/* Comment line */
return 0;
}
/* Extract the rule name */
name = line;
while(*line != '\0' && *line != '-' && *line != ':')
{
++line;
}
/* Extract the parent class, if it isn't implicit */
if(*line == '-')
{
*line++ = '\0';
parent = line;
while(*line != '\0' && *line != ':')
{
++line;
}
if(*line == ':')
{
*line++ = '\0';
}
implicit = 0;
}
else if(*line == ':')
{
*line++ = '\0';
implicit = 1;
}
else
{
implicit = 1;
}
if(implicit)
{
if(endsIn(name, "Expression"))
{
parent = "CodeExpression";
}
else if(endsIn(name, "Statement"))
{
parent = "CodeStatement";
}
else if(endsIn(name, "Collection"))
{
parent = "CollectionBase";
}
else
{
parent = "CodeObject";
}
}
/* Extract the contents of the rule */
while(*line != '\0')
{
if(*line == ' ' || *line == '\t' || *line == '\r' || *line ==
'\n')
{
*line++ = '\0';
}
else
{
/* Extract the contents entry */
contents = line;
while(*line != '\0' && *line != ' ' && *line != '\t' &&
*line != '\r' && *line != '\n')
{
++line;
}
if(*line != '\0')
{
*line++ = '\0';
}
/* Parse the entry into "type<name>" */
if(*contents == '$')
{
specialConstructors = 0;
++contents;
}
if(*contents == '?')
{
contentIsOptional[numContents] = 1;
++contents;
}
else
{
contentIsOptional[numContents] = 0;
}
if(*contents == '*')
{
contentIsParams[numContents] = 1;
++contents;
}
else if(*contents == '@')
{
contentIsParams[numContents] = 2;
++contents;
}
else
{
contentIsParams[numContents] = 0;
}
contentType[numContents] = contents;
while(*contents != '\0' && *contents != '<')
{
++contents;
}
if(*contents == '<')
{
*contents++ = '\0';
contentName[numContents] = contents;
while(*contents != '\0' && *contents != '>')
{
++contents;
}
*contents = '\0';
}
else
{
contentName[numContents] = "";
}
++numContents;
}
}
/* Done */
return 1;
}
/*
* Generate code for a collection class.
*/
static void generateCollectionCode(FILE *stream)
{
char *member = contentType[0];
/* Output the constructors */
fprintf(stream, "\t// Constructors.\n");
fprintf(stream, "\tpublic %s()\n", name);
fprintf(stream, "\t{\n\t}\n");
fprintf(stream, "\tpublic %s(%s[] value)\n", name, member);
fprintf(stream, "\t{\n");
fprintf(stream, "\t\tAddRange(value);\n");
fprintf(stream, "\t}\n");
fprintf(stream, "\tpublic %s(%s value)\n", name, name);
fprintf(stream, "\t{\n");
fprintf(stream, "\t\tAddRange(value);\n");
fprintf(stream, "\t}\n\n");
/* Output the properties */
fprintf(stream, "\t// Properties.\n");
fprintf(stream, "\tpublic %s this[int index]\n", member);
fprintf(stream, "\t{\n");
fprintf(stream, "\t\tget\n");
fprintf(stream, "\t\t{\n");
fprintf(stream, "\t\t\treturn (%s)(List[index]);\n", member);
fprintf(stream, "\t\t}\n");
fprintf(stream, "\t\tset\n");
fprintf(stream, "\t\t{\n");
fprintf(stream, "\t\t\tList[index] = value;\n");
fprintf(stream, "\t\t}\n");
fprintf(stream, "\t}\n\n");
/* Output the methods */
fprintf(stream, "\t// Methods.\n");
fprintf(stream, "\tpublic int Add(%s value)\n", member);
fprintf(stream, "\t{\n");
fprintf(stream, "\t\treturn List.Add(value);\n");
fprintf(stream, "\t}\n");
fprintf(stream, "\tpublic void AddRange(%s[] value)\n", member);
fprintf(stream, "\t{\n");
fprintf(stream, "\t\tforeach(%s e in value)\n", member);
fprintf(stream, "\t\t{\n");
fprintf(stream, "\t\t\tList.Add(e);\n");
fprintf(stream, "\t\t}\n");
fprintf(stream, "\t}\n");
fprintf(stream, "\tpublic void AddRange(%s value)\n", name);
fprintf(stream, "\t{\n");
fprintf(stream, "\t\tforeach(%s e in value)\n", member);
fprintf(stream, "\t\t{\n");
fprintf(stream, "\t\t\tList.Add(e);\n");
fprintf(stream, "\t\t}\n");
fprintf(stream, "\t}\n");
fprintf(stream, "\tpublic bool Contains(%s value)\n", member);
fprintf(stream, "\t{\n");
fprintf(stream, "\t\treturn List.Contains(value);\n");
fprintf(stream, "\t}\n");
fprintf(stream, "\tpublic void CopyTo(%s[] array, int index)\n",
member);
fprintf(stream, "\t{\n");
fprintf(stream, "\t\tList.CopyTo(array, index);\n");
fprintf(stream, "\t}\n");
fprintf(stream, "\tpublic bool IndexOf(%s value)\n", member);
fprintf(stream, "\t{\n");
fprintf(stream, "\t\treturn List.IndexOf(value);\n");
fprintf(stream, "\t}\n");
fprintf(stream, "\tpublic void Insert(int index, %s value)\n", member);
fprintf(stream, "\t{\n");
fprintf(stream, "\t\tList.Insert(index, value);\n");
fprintf(stream, "\t}\n");
fprintf(stream, "\tpublic void Remove(%s value)\n", member);
fprintf(stream, "\t{\n");
fprintf(stream, "\t\tint index = List.IndexOf(value);\n");
fprintf(stream, "\t\tif(index < 0)\n");
fprintf(stream, "\t\t{\n");
fprintf(stream, "\t\t\tthrow new
ArgumentException(S._(\"Arg_NotCollMember\"), \"value\");\n");
fprintf(stream, "\t\t}\n");
fprintf(stream, "\t\tList.RemoveAt(index);\n");
fprintf(stream, "\t}\n\n");
/* Output the class footer */
fprintf(stream, "}; // class %s\n\n", name);
}
/*
* Generate code for a specific constructor, if enabled.
*/
static void generateConstructor(FILE *stream, unsigned mask)
{
int posn;
int needComma;
/* Determine if this constructor is enabled */
for(posn = 0; posn < numContents; ++posn)
{
if(!(contentIsOptional[posn]) && (mask & (1 << posn)) == 0)
{
return;
}
}
/* Generate the constructor */
fprintf(stream, "\tpublic %s(", name);
needComma = 0;
for(posn = 0; posn < numContents; ++posn)
{
if((mask & (1 << posn)) == 0)
{
continue;
}
if(needComma)
{
fputs(", ", stream);
}
if(contentIsParams[posn] == 1)
{
fprintf(stream, "params %s[] _%s", contentType[posn],
contentName[posn]);
}
else if(contentIsParams[posn] == 2)
{
fprintf(stream, "%s[] _%s", contentType[posn],
contentName[posn]);
}
else
{
fprintf(stream, "%s _%s", contentType[posn],
contentName[posn]);
}
needComma = 1;
}
fprintf(stream, ")\n\t{\n");
for(posn = 0; posn < numContents; ++posn)
{
if((mask & (1 << posn)) == 0)
{
continue;
}
if(contentIsParams[posn])
{
fprintf(stream, "\t\tthis.%s.AddRange(_%s);\n",
contentName[posn], contentName[posn]);
}
else
{
fprintf(stream, "\t\tthis._%s = _%s;\n",
contentName[posn], contentName[posn]);
}
}
fprintf(stream, "\t}\n");
}
/*
* Generate code for a rule class.
*/
static void generateCode(FILE *stream)
{
int posn;
unsigned mask, maxMask;
/* Output the class header */
fprintf(stream, "[Serializable]\n");
fprintf(stream, "[ClassInterface(ClassInterfaceType.AutoDispatch)]\n");
fprintf(stream, "[ComVisible(true)]\n");
fprintf(stream, "public class %s : %s\n", name, parent);
fprintf(stream, "{\n");
fprintf(stream, "\n");
/* We need to use a different algorithm if this is a collection */
if(!strcmp(parent, "CollectionBase"))
{
generateCollectionCode(stream);
return;
}
/* Output the instance fields */
if(numContents > 0)
{
fprintf(stream, "\t// Internal state.\n");
for(posn = 0; posn < numContents; ++posn)
{
if(contentIsParams[posn])
{
fprintf(stream, "\tprivate %sCollection _%s;\n",
contentType[posn],
contentName[posn]);
}
else
{
fprintf(stream, "\tprivate %s _%s;\n",
contentType[posn],
contentName[posn]);
}
}
fprintf(stream, "\n");
}
/* Output the constructors */
fprintf(stream, "\t// Constructors.\n");
fprintf(stream, "\tpublic %s()\n", name);
fprintf(stream, "\t{\n\t}\n");
if(numContents > 0 && specialConstructors)
{
maxMask = (unsigned)(1 << numContents);
for(mask = 0; mask < maxMask; ++mask)
{
generateConstructor(stream, mask);
}
}
fprintf(stream, "\n");
/* Output the property accessors */
if(numContents > 0)
{
fprintf(stream, "\t// Properties.\n");
for(posn = 0; posn < numContents; ++posn)
{
if(!specialConstructors &&
endsIn(contentType[posn], "Collection"))
{
fprintf(stream, "\tpublic %s %s\n",
contentType[posn],
contentName[posn]);
fprintf(stream, "\t{\n\t\tget\n");
fprintf(stream, "\t\t{\n");
fprintf(stream, "\t\t\tif(_%s == null)\n",
contentName[posn]);
fprintf(stream, "\t\t\t{\n");
fprintf(stream, "\t\t\t\t_%s = new %s();\n",
contentName[posn],
contentType[posn]);
fprintf(stream, "\t\t\t}\n");
fprintf(stream, "\t\t\treturn _%s;\n",
contentName[posn]);
fprintf(stream, "\t\t}\n");
fprintf(stream, "\t}\n");
}
else if(contentIsParams[posn])
{
fprintf(stream, "\tpublic %sCollection %s\n",
contentType[posn],
contentName[posn]);
fprintf(stream, "\t{\n\t\tget\n");
fprintf(stream, "\t\t{\n");
fprintf(stream, "\t\t\tif(_%s == null)\n",
contentName[posn]);
fprintf(stream, "\t\t\t{\n");
fprintf(stream, "\t\t\t\t_%s = new
%sCollection();\n",
contentName[posn],
contentType[posn]);
fprintf(stream, "\t\t\t}\n");
fprintf(stream, "\t\t\treturn _%s;\n",
contentName[posn]);
fprintf(stream, "\t\t}\n");
fprintf(stream, "\t}\n");
}
else
{
fprintf(stream, "\tpublic %s %s\n",
contentType[posn],
contentName[posn]);
fprintf(stream, "\t{\n\t\tget\n");
fprintf(stream, "\t\t{\n");
fprintf(stream, "\t\t\treturn _%s;\n",
contentName[posn]);
fprintf(stream, "\t\t}\n");
fprintf(stream, "\t\tset\n");
fprintf(stream, "\t\t{\n");
fprintf(stream, "\t\t\t_%s = value;\n",
contentName[posn]);
fprintf(stream, "\t\t}\n");
fprintf(stream, "\t}\n");
}
}
fprintf(stream, "\n");
}
/* Output the class footer */
fprintf(stream, "}; // class %s\n\n", name);
}
/*
* Standard copyright message to add to the front of the output.
*/
static char const COPYRIGHT_MSG[] =
"/*\n"
" * This file is generated from rules.txt using gencdom - do not
edit.\n"
" *\n"
" * Copyright (C) 2002 Southern Storm Software, Pty Ltd.\n"
" *\n"
" * This program is free software; you can redistribute it and/or
modify\n"
" * it under the terms of the GNU General Public License as published
by\n"
" * the Free Software Foundation; either version 2 of the License, or\n"
" * (at your option) any later version.\n"
" *\n"
" * This program is distributed in the hope that it will be useful,\n"
" * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
" * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
" * GNU General Public License for more details.\n"
" *\n"
" * You should have received a copy of the GNU General Public License\n"
" * along with this program; if not, write to the Free Software\n"
" * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA\n"
" */\n\n";
/*
* Generate the standard file header.
*/
static void generateHeader(FILE *stream)
{
fputs(COPYRIGHT_MSG, stream);
fprintf(stream, "namespace System.CodeDom\n{\n");
fprintf(stream, "\n");
fprintf(stream, "#if !ECMA_COMPAT\n");
fprintf(stream, "\n");
fprintf(stream, "using System.Runtime.InteropServices;\n");
fprintf(stream, "using System.Collections;\n");
fprintf(stream, "using System.Collections.Specialized;\n");
fprintf(stream, "\n");
}
/*
* Generate the standard file footer.
*/
static void generateFooter(FILE *stream)
{
fprintf(stream, "#endif // !ECMA_COMPAT\n");
fprintf(stream, "\n");
fprintf(stream, "}; // namespace System.CodeDom\n");
}
--- NEW FILE ---
#
# rules.txt - Code generation rules for "System.CodeDom" classes.
#
# Copyright (C) 2002 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
#
# '-' Indicates the base class if it isn't implicit
# '?' Indicates an optional constructor argument
# '*' Indicates a "params Type[]" argument
# '@' Indicates a "Type[]" argument
# '$' Indicates that no special constructors should be generated
CodeArgumentReferenceExpression: String<ParameterName>
CodeArrayIndexerExpression:
CodeExpression<TargetObject> *CodeExpression<Indices>
CodeAssignStatement: CodeExpression<Left> CodeExpression<Right>
CodeAttributeArgumentCollection: CodeAttributeArgument
CodeAttributeArgument-Object:
?String<Name> CodeExpression<Value>
CodeAttributeDeclarationCollection: CodeAttributeDeclaration
CodeAttributeDeclaration-Object:
String<Name> address@hidden<Arguments>
CodeBaseReferenceExpression
CodeBinaryOperatorExpression:
CodeExpression<Left> CodeBinaryOperatorType<Operator>
CodeExpression<Right>
CodeCatchClauseCollection: CodeCatchClause
CodeComment: String<Text> ?bool<DocComment>
CodeCommentStatementCollection: CodeCommentStatement
CodeCompileUnit:
$CodeAttributeDeclarationCollection<AssemblyCustomAttributes> \
CodeNamespaceCollection<Namespaces> \
StringCollection<ReferencedAssemblies>
CodeConstructor-CodeMemberMethod:
$CodeExpressionCollection<BaseConstructorArgs> \
CodeExpressionCollection<ChainedConstructorArgs>
CodeDelegateCreateExpression:
CodeTypeReference<DelegateType> CodeExpression<TargetObject> \
String<MethodName>
CodeDelegateInvokeExpression:
CodeExpression<TargetObject> address@hidden<Parameters>
CodeDirectionExpression: FieldDirection<Direction> CodeExpression<Expression>
CodeEntryPointMethod-CodeMemberMethod
CodeEventReferenceExpression:
CodeExpression<TargetObject> String<EventName>
CodeExpressionCollection: CodeExpression
CodeExpression-CodeObject
CodeExpressionStatement: CodeExpression<Expression>
CodeFieldReferenceExpression:
CodeExpression<TargetObject> String<FieldName>
CodeGotoStatement: String<Label>
CodeIndexerExpression:
CodeExpression<TargetObject> *CodeExpression<Indices>
CodeIterationStatement:
CodeStatement<InitStatement> CodeExpression<TestExpression> \
CodeStatement<IncrementStatement> *CodeStatement<Statements>
CodeLabeledStatement: String<Label> ?CodeStatement<Statement>
CodeLinePragma: String<FileName> int<LineNumber>
CodeMemberProperty:
$CodeStatementCollection<GetStatements> \
bool<HasGet> bool<HasSet> \
CodeTypeReferenceCollection<ImplementationTypes> \
CodeParameterDeclarationExpressionCollection<Parameters> \
CodeTypeReference<PrivateImplementationType> \
CodeStatementCollection<SetStatements> \
CodeTypeReference<Type>
CodeMethodReferenceExpression: CodeExpression<TargetObject> String<MethodName>
CodeMethodReturnStatement: CodeExpression<Expression>
CodeNamespaceCollection: CodeNamespace
CodeParameterDeclarationExpressionCollection:
CodeParameterDeclarationExpression
CodePrimitiveExpression: Object<Value>
CodePropertyReferenceExpression:
CodeExpression<TargetObject> String<PropertyName>
CodePropertySetValueExpression
CodeSnippetStatement: String<Value>
CodeSnippetTypeMember-CodeTypeMember: String<Text>
CodeStatementCollection: CodeStatement
CodeStatement: $CodeLinePragma<LinePragma>
CodeThisReferenceExpression
CodeThrowExceptionStatement: CodeExpression<ToThrow>
CodeTryCatchFinallyStatement:
@CodeStatement<TryStatements> @CodeCatchClause<CatchClauses> \
address@hidden<FinallyStatements>
CodeTypeConstructor-CodeMemberMethod
CodeTypeDeclarationCollection: CodeTypeDeclaration
CodeTypeMemberCollection: CodeTypeMember
CodeTypeReferenceCollection: CodeTypeReference
#
# The following classes must be defined manually, because they are
# too complex or odd to subject to rule-based code generation:
#
# CodeArrayCreateExpression
# CodeAttachEventStatement
# CodeCastExpression
# CodeCatchClause
# CodeCommentStatement
# CodeConditionStatement
# CodeMemberEvent
# CodeMemberField
# CodeMemberMethod
# CodeMethodInvokeExpression
# CodeNamespace
# CodeNamespaceImportCollection
# CodeNamespaceImport
# CodeObjectCreateExpression
# CodeObject
# CodeParameterDeclarationExpression
# CodeRemoveEventStatement
# CodeSnippetCompileUnit
# CodeTypeDeclaration
# CodeTypeDelegate
# CodeTypeMember
# CodeTypeOfExpression
# CodeTypeReference
# CodeTypeReferenceExpression
# CodeVariableDeclarationStatement
#
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Dotgnu-pnet-commits] CVS: pnetlib/System/CodeDom gencdom.c,NONE,1.1 rules.txt,NONE,1.1,
Rhys Weatherley <address@hidden> <=