/* Code generator for the Programming languages. Copyright (c) 2009-2014 The Regents of the University of California. All rights reserved. Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, modify, and distribute this software and its documentation for any purpose, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. PT_COPYRIGHT_VERSION_2 COPYRIGHTENDKEY */ package ptolemy.cg.kernel.generic.program; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import ptolemy.actor.Actor; import ptolemy.actor.CompositeActor; import ptolemy.actor.TypedIOPort; import ptolemy.cg.kernel.generic.CodeGeneratorAdapter; import ptolemy.cg.kernel.generic.CodeGeneratorUtilities; import ptolemy.cg.kernel.generic.GenericCodeGenerator; import ptolemy.cg.lib.PointerToken; import ptolemy.data.BooleanToken; import ptolemy.data.IntToken; import ptolemy.data.expr.Parameter; import ptolemy.data.expr.StringParameter; import ptolemy.data.type.ArrayType; import ptolemy.data.type.BaseType; import ptolemy.data.type.MatrixType; import ptolemy.data.type.RecordType; import ptolemy.data.type.Type; import ptolemy.kernel.CompositeEntity; import ptolemy.kernel.attributes.URIAttribute; import ptolemy.kernel.util.Attribute; import ptolemy.kernel.util.IllegalActionException; import ptolemy.kernel.util.InternalErrorException; import ptolemy.kernel.util.KernelException; import ptolemy.kernel.util.NameDuplicationException; import ptolemy.kernel.util.NamedObj; import ptolemy.kernel.util.StreamListener; import ptolemy.kernel.util.Workspace; import ptolemy.util.JVMBitWidth; import ptolemy.util.StreamExec; import ptolemy.util.StringUtilities; /////////////////////////////////////////////////////////////////// //// ProgramCodeGenerator /** Generate a programming language version of a model. * *
This base class contains parameters and methods common to * all programming languages.
* * @author Bert Rodiers * @version $Id: ProgramCodeGenerator.java 70402 2014-10-23 00:52:20Z cxh $ * @since Ptolemy II 10.0 * @Pt.ProposedRating red (rodiers) * @Pt.AcceptedRating red (rodiers) */ public class ProgramCodeGenerator extends GenericCodeGenerator { /** Create a new instance of the ProgramCodeGenerator. * @param container The container. * @param name The name of the ProgramCodeGenerator. * @param outputFileExtension The extension of the output file. * (for example c in case of C and java in case of Java) * @param templateExtension The extension of the template files. * (for example c in case of C and j in case of Java). * @exception IllegalActionException If the super class throws the * exception or error occurs when setting the file path. * @exception NameDuplicationException If the super class throws the * exception or an error occurs when setting the file path. */ public ProgramCodeGenerator(NamedObj container, String name, String outputFileExtension, String templateExtension) throws IllegalActionException, NameDuplicationException { super(container, name, outputFileExtension); _templateExtension = templateExtension; generateComment = new Parameter(this, "generateComment"); generateComment.setTypeEquals(BaseType.BOOLEAN); generateComment.setExpression("true"); inline = new Parameter(this, "inline"); inline.setTypeEquals(BaseType.BOOLEAN); inline.setExpression("true"); maximumLinesPerBlock = new Parameter(this, "maximumLinesPerBlock"); maximumLinesPerBlock.setTypeEquals(BaseType.INT); maximumLinesPerBlock.setExpression("2500"); measureTime = new Parameter(this, "measureTime"); measureTime.setTypeEquals(BaseType.BOOLEAN); measureTime.setExpression("false"); run = new Parameter(this, "run"); run.setTypeEquals(BaseType.BOOLEAN); run.setExpression("true"); runCommand = new StringParameter(this, "runCommand"); // Set it to a default so that derived classes may override it. runCommand.setExpression(_runCommandDefault); useMake = new Parameter(this, "useMake"); useMake.setTypeEquals(BaseType.BOOLEAN); useMake.setExpression("true"); _substituteMap = CodeGeneratorUtilities.newMap(this); variablesAsArrays = new Parameter(this, "variablesAsArrays"); variablesAsArrays.setTypeEquals(BaseType.BOOLEAN); variablesAsArrays.setExpression("false"); verbosity = new Parameter(this, "verbosity"); verbosity.setTypeEquals(BaseType.INT); verbosity.setExpression("0"); generatorPackageList.setExpression("generic.program"); } /////////////////////////////////////////////////////////////////// //// parameters //// /** If true, generate comments in the output code; otherwise, * no comments is generated. The default value is a parameter * with the value true. */ public Parameter generateComment; /** If true, generate file with no functions. If false, generate * file with functions. The default value is a parameter with the * value false. */ public Parameter inline; /** The maximum number of lines per block. Maximum number of * lines in initialize(), postfire() and wrapup() methods. This * parameter is used to make smaller methods so that compilers * take less time to compile. Most target languages have limits * to the size of a block or method. If a block or method has * more lines than this value, then some code generators may try * to split of the code. Note that this is very experimental. * The default value is an integer with value 2500. */ public Parameter maximumLinesPerBlock; /** If true, generate code to measure the execution time. * The default value is a parameter with the value false. */ public Parameter measureTime; /** If true, then run the generated code. The default * value is a parameter with the value true. */ public Parameter run; /** The command to use to run the generated code if the * useMake parameter is false. The initial default value * is "make -f @modelName@.mk run". Various '@' delimited * key/value pairs will be automatically substituted. In the * default case @modelName@ will be replaced with a sanitized * (Java-safe) version of the model name. * *If the string "@help:all@" appears, then all the key/value * pairs are echoed at run time, though this may not result in a * syntactically correct command.
* *If useMake is true, then the value of this parameter * is ignored.
*/ public StringParameter runCommand; /** If true, then use the 'make' command to compile and run * the generated code. The default is true; */ public Parameter useMake; /** If true, then generate code that puts variables into arrays; * otherwise, use standalone variables. This parameter is used * for very large models that would otherwise generate code that * cannot be compiled by the Java compiler. If this is the case, * then javac will produce an error message like "too many * constants". The default value is a parameter with the value * false. */ public Parameter variablesAsArrays; /** Level of verbosity in comments and other output. Levels * greater than 0 will cause the code generator to generate more * detailed information about the operation of the code * generator. If the value of the verbosity parameter is * greater than 9, then the comment is prepended with the name of * the method that called the method that called this method. * This is useful for debugging. The default is an integer with * the value 0, which indicates that the lowest level of * verbosity. */ public Parameter verbosity; /////////////////////////////////////////////////////////////////// //// public methods //// /** Add a modified variable. * @param variable The variable to add to the Set * @exception IllegalActionException Not thrown in this base class. * @see #getModifiedVariables() */ final public void addModifiedVariables(Parameter variable) throws IllegalActionException { _modifiedVariables.add(variable); } /** If the attribute is the verbosity attribute, then if * its value is 1, set a debug listener on the code generator. * @param attribute The attribute that changed. * @exception IllegalActionException If the change is not acceptable * to this container. */ @Override public void attributeChanged(Attribute attribute) throws IllegalActionException { if (attribute == variablesAsArrays) { if (((BooleanToken) variablesAsArrays.getToken()).booleanValue()) { _variablesAsArrays = true; } else { _variablesAsArrays = false; } } else if (attribute == verbosity) { int verbosityLevel = ((IntToken) verbosity.getToken()).intValue(); if (verbosityLevel == 1) { addDebugListener(new StreamListener()); } } super.attributeChanged(attribute); } /** Clone the attribute into the specified workspace. * @param workspace The workspace for the new object. * @return A new attribute. * @exception CloneNotSupportedException If a derived class contains * an attribute that cannot be cloned. */ @Override public Object clone(Workspace workspace) throws CloneNotSupportedException { ProgramCodeGenerator newObject = (ProgramCodeGenerator) super .clone(workspace); try { newObject._substituteMap = CodeGeneratorUtilities.newMap(this); } catch (IllegalActionException ex) { throw new CloneNotSupportedException(ex.getMessage()); } return newObject; } /** * Get the corresponding type in code generation from the given Ptolemy * type. * @see #ptolemyType(String) * @param ptType The given Ptolemy type. * @return The code generation type. */ public String codeGenType(Type ptType) { // Do not make this static as Java Codegen requires that it be // non static. // If this is static, then this command will fail: // $PTII/bin/ptcg -generatorPackage ptolemy.codegen.java $PTII/ptolemy/codegen/java/actor/lib/colt/test/auto/ColtBinomialSelector.xml if (ptType == BaseType.GENERAL) { return "Token"; } // FIXME: this may be the case for unconnected ports. if (ptType == BaseType.UNKNOWN) { return "Token"; } if (ptType == BaseType.SCALAR) { // FIXME: do we need a codegen type for scalar? return "Scalar"; } // FIXME: We may need to add more types. // FIXME: We have to create separate type for different matrix types. String result = ptType == BaseType.INT ? "Int" : ptType == BaseType.LONG ? "Long" : ptType == BaseType.STRING ? "String" : ptType == BaseType.DOUBLE ? "Double" : ptType == BaseType.BOOLEAN ? "Boolean" : ptType == BaseType.UNSIGNED_BYTE ? "UnsignedByte" : ptType == PointerToken.POINTER ? "Pointer" : ptType == BaseType.COMPLEX ? "Complex" // FIXME: Why do we have to use equals with BaseType.OBJECT? : ptType.equals(BaseType.OBJECT) ? "Object" //: ptType == BaseType.OBJECT ? "Object" : null; if (result == null) { if (ptType instanceof ArrayType) { // This change breaks $PTII/bin/ptcg $PTII/ptolemy/codegen/c/actor/lib/colt/test/auto/BinomialSelectorTest.xml if (isPrimitive(((ArrayType) ptType).getElementType())) { result = codeGenType(((ArrayType) ptType).getElementType()) + "Array"; } else { result = "Array"; } } else if (ptType instanceof MatrixType) { //result = ptType.getClass().getSimpleName().replace("Type", ""); result = "Matrix"; } else if (ptType instanceof RecordType) { RecordType rType = (RecordType) ptType; StringBuffer arrayResult = new StringBuffer(); for (String label : rType.labelSet()) { Type t = null; try { t = (Type) rType.getTypeTerm(label).getValue(); } catch (IllegalActionException e) { } arrayResult.append(codeGenType(t) + ","); } result = arrayResult.toString().substring(0, arrayResult.length() - 1); } } if (result == null || result.length() == 0) { System.out .println("Cannot resolve codegen type from Ptolemy type: " + ptType); } return result; } /** Return a formatted comment containing the * specified string with a specified indent level. * @param comment The string to put in the comment. * @param indentLevel The indentation level. * @return A formatted comment. */ public String comment(int indentLevel, String comment) { try { if (generateComment.getToken() == BooleanToken.TRUE) { return StringUtilities.getIndentPrefix(indentLevel) + _formatComment(comment); } } catch (IllegalActionException e) { // do nothing. } return ""; } /** Return a formatted comment containing the * specified string. In this base class, the * comments is a C-style comment, which begins with * "\/*" and ends with "*\/". * @param comment The string to put in the comment. * @return A formatted comment. */ @Override public String comment(String comment) { try { if (generateComment.getToken() == BooleanToken.TRUE) { return _formatComment(comment); } } catch (IllegalActionException e) { // do nothing. } return ""; } /** Generate code that defines a constant. In C, generate a * #define, in Java, generate a static final. * @param constant The name of the constant to be defined * @param type A string representing the type. In C, this * parameter is ignored. * @param value The value of the constant. * @return A string that defines a constant. * In this base class, a comment with the values of the * arguments is returned. */ public String generateConstantDefinition(String constant, String type, String value) { return comment(constant + " " + type + " " + value); } /** Generate The fire function code. This method is called when * the firing code of each actor is not inlined. In the default, * each actor's firing code is in a function with the name that * is returned by * {@link #generateFireFunctionMethodName(NamedObj)}. Derived * classes such as JavaCodeGenerator may put the fire functions * in inner classes so as to reduce the Java file size. * * @return The fire function code of the containing composite actor. * @exception IllegalActionException If thrown while generating fire code. */ public String generateFireFunctionCode() throws IllegalActionException { StringBuffer code = new StringBuffer(); NamedProgramCodeGeneratorAdapter adapter = (NamedProgramCodeGeneratorAdapter) getAdapter(getContainer()); code.append(adapter.generateFireFunctionCode()); return code.toString(); } /** Generate the closing code for a group of fire functions common * to a Composite Actor. This method is called when the firing * code of each actor is not inlined. * * @return In this base class, return the empty string. Derived * classes, such as the JavaCodeGenerator could return the * end of an inner class. */ public String generateFireFunctionCompositeEnd() { return ""; } /** Generate the initial code for a group of fire functions common * to a Composite Actor. This method is called when the firing * code of each actor is not inlined. * * @param className The name of the class to include in the * initial code. * @return In this base class, return the empty string. Derived * classes, such as the JavaCodeGenerator could return the * start of an inner class. */ public String generateFireFunctionCompositeStart(String className) { return ""; } /** Generate the fire function method invocation. This method is called * when the firing code of each actor is not inlined. In this * base class, each actor's firing code is in a function with the * same name as that of the actor. * * @param namedObj The named object for which the name is generated. * @return The name of the fire function invocation. * @exception IllegalActionException Not thrown in this base class. * Derived classes should throw this exception if there are problems * accessing the name or generating the name. */ public String generateFireFunctionMethodInvocation(NamedObj namedObj) throws IllegalActionException { return generateFireFunctionMethodName(namedObj); } /** Generate the fire function method name. This method is called * when the firing code of each actor is not inlined. In this * base class, each actor's firing code is in a function with the * same name as that of the actor. * * @param namedObj The named object for which the name is generated. * @return The name of the fire function method. * @exception IllegalActionException Not thrown in this base class. * Derived classes should throw this exception if there are problems * accessing the name or generating the name. */ public String generateFireFunctionMethodName(NamedObj namedObj) throws IllegalActionException { return TemplateParser.escapeName(CodeGeneratorAdapter .generateName(namedObj)); } /** Generate the fire function variable name and method * name. This method is called when the firing code of each actor * is not inlined. * * @param namedObj The named object for which the name is generated. * @return An array of two elements. In this base class, the * first element is the empty string, the second element is the * method name. In derived classes, the first element is a * String that contains the variable name, the second is the name * of the method. * @exception IllegalActionException If thrown while generating fire code. */ public String[] generateFireFunctionVariableAndMethodName(NamedObj namedObj) throws IllegalActionException { String[] results = new String[2]; results[0] = ""; results[1] = CodeGeneratorAdapter.generateName(namedObj); return results; } /** Generate the fire function variable declaration. This method * is called when the firing code of each actor is not inlined. * In this base class, the empty string is returned. Derived * classes, such as JavaCodeGenerator, could return a variable * declaration that instantiates an inner class. * *The purpose of this method is to allow derived generators * to generate code in inner classes and thus allow the compilation * of large models.
* * @param namedObj The named object for which the name is generated. * @return In this baseclass, return the empty string. * @exception IllegalActionException Not thrown in this base class. * Derived classes should throw this exception if there are problems * accessing the name or generating the name. */ public String generateFireFunctionVariableDeclaration(NamedObj namedObj) throws IllegalActionException { return ""; } /** Return true if the input contains code. * In this context, code is considered to be anything other * than comments and whitespace. * @param code The string to check for code. * @return True if the string contains anything other than * white space or comments */ public static boolean containsCode(String code) { if (code == null) { return false; } return code.replaceAll("/\\*[^*]*\\*/", "").replaceAll("[ \t\n\r]", "") .length() > 0; } /** * Return the code associated with initialization of the containing * composite actor. This method calls the generateInitializeCode() * method of the code generator adapter associated with the model director. * @return The initialize code of the containing composite actor. * @exception IllegalActionException If the adapter class for the model * director cannot be found or if an error occurs when the director * adapter generates initialize code. */ public String generateInitializeCode() throws IllegalActionException { StringBuffer code = new StringBuffer(); //code.append(comment("Initialize " + getContainer().getFullName())); NamedProgramCodeGeneratorAdapter adapter = (NamedProgramCodeGeneratorAdapter) getAdapter(getContainer()); code.append(adapter.generateInitializeCode()); return code.toString(); } /** Return the closing entry code, if any. * @return the closing entry code. */ public String generateClosingEntryCode() { return comment("closing entry code"); } /** Return the closing exit code, if any. * @return the closing exit code. */ public String generateClosingExitCode() { return comment("closing exit code"); } /** Generate the initialization procedure entry point. * @return a string for the initialization procedure entry point. * @exception IllegalActionException Not thrown in this base class. */ public String generateInitializeEntryCode() throws IllegalActionException { return comment("initialization entry code"); } /** Generate the initialization procedure exit point. * @return a string for the initialization procedure exit point. * @exception IllegalActionException Not thrown in this base class. */ public String generateInitializeExitCode() throws IllegalActionException { return comment("initialization exit code"); } /** Generate the initialization procedure name. * @return a string for the initialization procedure name. * @exception IllegalActionException Not thrown in this base class. */ public String generateInitializeProcedureName() throws IllegalActionException { return ""; } /** Generate line number and file name information. * @param lineNumber The line number of the source file or * file containing code blocks. * @param filename The name of the source file or file containing * code blocks. * @return In this base class, return the empty string. */ public String generateLineInfo(int lineNumber, String filename) { return ""; } /** Generate the main entry point. * @return Return the definition of the main entry point for a program. * @exception IllegalActionException Not thrown in this base class. */ public String generateMainEntryCode() throws IllegalActionException { return comment("main entry code"); } /** Generate the main exit point. * @return Return a string that declares the end of the main() function. * @exception IllegalActionException Not thrown in this base class. */ public String generateMainExitCode() throws IllegalActionException { return comment("main exit code"); } /** Generate the package statement, if any. * Derived classes, such as the Java code generator, might generate * a package statement here. * @return In this base class, return the empty string. * @exception IllegalActionException Not thrown in this base class. */ public String generatePackageStatement() throws IllegalActionException { return ""; } /** * Generate sanitized name for the given port. * If the {@link #variablesAsArrays} parameter is true, then * a reference into an array of the appropriate type (ports_int[], * ports_double[] etc.) is returned. Otherwise, the name of * the port with any underscores converted to periods is returned. * See {@link ptolemy.cg.adapter.generic.program.procedural.java.adapters.ptolemy.domains.sdf.kernel.SDFDirector#generateInitializeCode()} for where the arrays are initialized. * @param port The port for which the name is generated. * @param portName The sanitized name of the port. * @param bufferSize The size of the port buffer. * @return The name of the port as an array element. */ public String generatePortName(TypedIOPort port, String portName, int bufferSize) { try { if (!((BooleanToken) variablesAsArrays.getToken()).booleanValue()) { return portName.replace(".", "_"); } } catch (IllegalActionException ex) { // Ignore ex.printStackTrace(); } // Generate the port name as an element in array. // This is done to make the generate java file easier to compile. // There is similar code in JavaCodeGenerator. // The idea is that for each type, we have an array // that contain the variables for that type. // This means that we will have many less variables, which will // get around javac's "too many constants" message // (See http://marxsoftware.blogspot.com/2010/01/reproducing-too-many-constants-problem.html) // However, we don't want to search the arrays while // generating code, so we have a separate HashMap that // that is used at code generation time to map from // names to the index in the corresponding type array. String typeName = targetType(port.getType()); // We will generate code that uses three different arrays. // The arrays differ in the number of dimensions. // Here, the arrays are represented as maps. // Determine which map to use. We delay instantiation // until we need the map so that we don't generate unnecessary // code. HashMapIn this base class, since we don't know what the target * language will be, the first element is the empty string, the * second element is the code argument.
* * @param linesPerMethod The number of lines that should go into * each method. * @param prefix The prefix to use when naming functions that * are created * @param code The method body to be split. * @return An array of two Strings, where the first element * is the new definitions (if any), and the second element * is the new body. If the number of lines in the code parameter * is less than linesPerMethod, then the first element will be * the empty string and the second element will be the value of * the code parameter. In this base class, the first element * is always the empty string and the second element is the value * of the code parameter. * @exception IOException If thrown while reading the code. */ public String[] splitLongBody(int linesPerMethod, String prefix, String code) throws IOException { String[] results = { "", code }; return results; } /** Split a long variable declaration body into multiple blocks * or files. *In this base class, since we don't know what the target * language will be, the first element is the empty string, the * second element is the code argument.
* * @param linesPerMethod The number of lines that should go into * each method. * @param prefix The prefix to use when naming functions that * are created * @param code The variable declarations to be split. * @return A list of at least two elements. If the code has less * than the value of the maximumNumberOfLinesPerBlock * parameter lines, then the first element is empty, the second * element contains the contents of the code parameter. If the * code has more lines than maximumLinesPerBlock, * then the first element contains the declarations necessary for * the include files section and the second element and * successive elements contain the declarations. Each * declaration should be placed into a file that corresponds with * the include or import listed in the first element. * @exception IOException If thrown while reading the code. */ public List$HOME
, the name of the
* model is Foo
and the generatorPackage
* is ptolemy.codegen.c
, then the file that is
* written will be $HOME/Foo.c
* This method is the main entry point.
* @param code The given string buffer.
* @return The return value of the last subprocess that was executed.
* or -1 if no commands were executed.
* @exception KernelException If the target file cannot be overwritten
* or write-to-file throw any exception.
*/
@Override
protected int _generateCode(StringBuffer code) throws KernelException {
// Record the current time so that we can monitor performance of the
// code generator by printing messages whenever any part of the code
// generation process takes more than 10 seconds.
long startTime = new Date().getTime();
long overallStartTime = startTime;
_reset();
_sanitizedModelName = CodeGeneratorAdapter.generateName(_model);
// Each time a .dll file is generated, we must use a different name
// for it so that it can be loaded without restarting vergil.
CompositeActor container = (CompositeActor) getContainer();
if (container instanceof ptolemy.cg.lib.CompiledCompositeActor) {
_sanitizedModelName = ((ptolemy.cg.lib.CompiledCompositeActor) container)
.getSanitizedName();
}
boolean inlineValue = ((BooleanToken) inline.getToken()).booleanValue();
// Analyze type conversions that may be needed.
// This must be called before any code is generated.
_analyzeTypeConversions();
// Report time consumed if appropriate.
startTime = _printTimeAndMemory(startTime,
"CodeGenerator.analyzeTypeConvert() consumed: ");
// Add include directories and libraries specified by actors.
_addActorIncludeDirectories();
_addActorLibraries();
// Generate code.
// We use the strategy pattern here, calling methods that
// can be overridden in derived classes. We mostly invoke
// these methods in the order that the code will be
// executed, except for some exceptions as noted.
// Perform any setup in the adapter. EmbeddedCodeActor uses this.
_setupAdapter();
String preinitializeCode = _generatePreinitializeCode();
// Typically, the preinitialize code consists of variable
// declarations. However, AutoAdapter generates method calls
// that instantiate wrapper TypedCompositeActors, so we need
// to invoke those method calls.
String preinitializeMethodEntryCode = _generatePreinitializeMethodEntryCode();
String preinitializeMethodBodyCode = _generatePreinitializeMethodBodyCode();
String preinitializeMethodExitCode = _generatePreinitializeMethodExitCode();
String preinitializeProcedureName = _generatePreinitializeMethodProcedureName();
// FIXME: The rest of these methods should be made protected
// like the ones called above. The derived classes also need
// to be fixed.
String initializeCode = generateInitializeCode();
// The StaticSchedulingCodeGenerator._generateBodyCode() reads
// _postfireCode to see if we should include a call to postfire or
// not, so we need to call generatePostfireCode() before
// call _generateBodyCode().
//_postfireCode = generatePostfireCode();
String bodyCode = _generateBodyCode();
String mainEntryCode = generateMainEntryCode();
String mainExitCode = generateMainExitCode();
String initializeEntryCode = generateInitializeEntryCode();
String initializeExitCode = generateInitializeExitCode();
String initializeProcedureName = generateInitializeProcedureName();
//String postfireEntryCode = generatePostfireEntryCode();
//String postfireExitCode = generatePostfireExitCode();
///*String postfireProcedureName =*/generatePostfireProcedureName();
String wrapupEntryCode = generateWrapupEntryCode();
String wrapupExitCode = generateWrapupExitCode();
String wrapupProcedureName = generateWrapupProcedureName();
String fireFunctionCode = null;
if (!inlineValue) {
fireFunctionCode = generateFireFunctionCode();
}
String wrapupCode = generateWrapupCode();
String closingEntryCode = generateClosingEntryCode();
String closingExitCode = generateClosingExitCode();
String variableInitCode = generateVariableInitialization();
// Generate shared code. Some adapter optionally add methods
// to the shared code block, so we generate the shared code as
// late as possible. However, we have to generateSharedCode()
// before generateTypeConvertCode() so that any polymorphic
// codegen token methods used in the shared code are recorded. See
// $PTII/bin/ptcg -language java $PTII/ptolemy/cg/adapter/generic/program/procedural/java/adapters/ptolemy/actor/lib/test/auto/arrayType18.xml
String sharedCode = _generateSharedCode();
// generate type resolution code has to be after
// fire(), wrapup(), preinit(), init()...
String typeResolutionCode = generateTypeConvertCode();
// Generating variable declarations needs to happen after buffer
// sizes are set(?). Also, we want to generate the type convert code
// so that we know if we need to import Array etc.
ListTypically, the preinitialize code consists of variable * declarations. However, AutoAdapter generates method calls * that instantiate wrapper TypedCompositeActors, so we need * to invoke those method calls.
* * @return a string for the preinitialization method body. * @exception IllegalActionException Not thrown in this base class. */ protected String _generatePreinitializeMethodBodyCode() throws IllegalActionException { StringBuffer code = new StringBuffer(); NamedProgramCodeGeneratorAdapter adapter = (NamedProgramCodeGeneratorAdapter) getAdapter(getContainer()); try { // Delegate to the container to generate preinitialize code. code.append(adapter.generatePreinitializeMethodBodyCode()); } catch (Throwable throwable) { throw new IllegalActionException(adapter.getComponent(), throwable, "Failed to generate preinitialize method body code"); } return code.toString(); } /** Generate the preinitialization procedure entry point. * @return a string for the preinitialization procedure entry point. * @exception IllegalActionException Not thrown in this base class. */ protected String _generatePreinitializeMethodEntryCode() throws IllegalActionException { return comment("preinitialization entry code"); } /** Generate the preinitialization procedure exit point. * @return a string for the preinitialization procedure exit point. * @exception IllegalActionException Not thrown in this base class. */ protected String _generatePreinitializeMethodExitCode() throws IllegalActionException { return comment("preinitialization exit code"); } /** Generate the preinitialization procedure name. * @return a string for the preinitialization procedure name. * @exception IllegalActionException Not thrown in this base class. */ protected String _generatePreinitializeMethodProcedureName() throws IllegalActionException { return ""; } /** Instantiate the given code generator adapter. * @param component The given component. * @param componentClass The class of the component to be instantiated. * The constructor for class named by the adapterClassName argument * must take an argument of the class componentClass. * @param adapterClassName The dot separated name of the adapter. * @return The code generator adapter. * @exception IllegalActionException If the adapter class cannot be found. */ @Override protected CodeGeneratorAdapter _instantiateAdapter(Object component, Class> componentClass, String adapterClassName) throws IllegalActionException { ProgramCodeGeneratorAdapter adapter = (ProgramCodeGeneratorAdapter) super ._instantiateAdapter(component, componentClass, adapterClassName); try { Class> templateParserClass = _templateParserClass(); if (templateParserClass != null) { adapter.setTemplateParser((TemplateParser) templateParserClass .newInstance()); } } catch (InstantiationException e) { throw new InternalErrorException(e); } catch (IllegalAccessException e) { throw new InternalErrorException(e); } return adapter; } /** Return the prototype for fire functions. * @return In this base class, return "()". * Derived classes, such as the C code generator adapter * might return "(void)". */ protected String _getFireFunctionArguments() { return "()"; } /** Generate the code for printing the execution time since * the code generated by _recordStartTime() was called. * This base class only generates a comment. * @return Return the code for printing the total execution time. */ protected String _printExecutionTime() { return comment("Print execution time."); } /** Generate the code for recording the current time. * This base class only generates a comment. * @return Return the code for recording the current time. */ protected String _recordStartTime() { return comment("Record current time."); } /** Reset the code generator. * @exception IllegalActionException Not thrown in this base class, * thrown by the parent if the container of the model * cannot be set to null. */ @Override protected void _reset() throws IllegalActionException { super._reset(); // Reset the indent to zero. _indent = 0; _newTypesUsed.clear(); _tokenFuncUsed.clear(); _typeFuncUsed.clear(); if (_substituteMap != null) { _substituteMap.clear(); } } /** Perform any setup or initialization of the adapter. * Note that this is not the Ptolemy initialize() method, * this method merely sets up any codegen-time variables * in the adapters. * @exception IllegalActionException If an error occurrs while * initializing an adapter. */ protected void _setupAdapter() throws IllegalActionException { NamedProgramCodeGeneratorAdapter adapter = (NamedProgramCodeGeneratorAdapter) getAdapter(getContainer()); adapter.setupAdapter(); } /** Split the variable declaration into possibly two sections. * @param suffix The suffix to use when naming functions that * are created. * @param code The variable declarations to be split. * @return A list of at least two elements. If the code has less * than maximumLinesPerBlock lines, then the first * element is empty, the second element contains the contents of * the code parameter. If the code has more lines than * maximumLinesPerBlock, then the first element contains the * declarations necessary for the include files section and the * second element and successive elements contain the * declarations. Each declaration should be placed into a file * that corresponds with the include or import listed in the * first element. */ protected ListIf a .mk.in
file with the name of the sanitized model
* name, then that file is used as a template. For example, if the
* model name is Foo
and the file Foo.mk.in
* exists, then the file Foo.mk.in
is used as a makefile
* template.
*
*
If no .mk.in
file is found, then the makefile
* template can be found by looking up a resource name
* makefile.in in the package named by the
* generatorPackage parameter. Thus, if the
* generatorPackage has the value "ptolemy.codegen.c",
* then we look for the resource "ptolemy.codegen.c.makefile.in", which
* is usually found as $PTII/ptolemy/codegen/c/makefile.in
.
*
*
The makefile is written to a directory named by the * codeDirectory parameter, with a file name that is a * sanitized version of the model name, and a ".mk" extension. * Thus, for a model named "Foo", we might generate a makefile in * "$HOME/codegen/Foo.mk". *
Under Java under Windows, your $HOME
variable
* is set to the value of the user.home
System property,
* which is usually something like
* C:\Documents and Settings\yourlogin
, thus
* for user mrptolemy
the makefile would be
* C:\Documents and Settings\mrptolemy\codegen\Foo.mk
.
*
*
The following variables are substituted *
@modelName@
* @CLASSPATHSEPARATOR@
* @PTJNI_NO_CYGWIN@
,
* @PTJNI_SHAREDLIBRARY_CFLAG@
,
* @PTJNI_SHAREDLIBRARY_LDFLAG@
,
* @PTJNI_SHAREDLIBRARY_PREFIX@
* @PTJNI_SHAREDLIBRARY_SUFFIX@
@PTJavaCompiler@
javac