Docsity
Docsity

Prepare for your exams
Prepare for your exams

Study with the several resources on Docsity


Earn points to download
Earn points to download

Earn points by helping other students or get them with a premium plan


Guidelines and tips
Guidelines and tips

Translating L-System Grammar Specifications to Java: A Study of the Growth Framework, Study notes of Electrical and Electronics Engineering

The process of translating l-system grammar specifications to the java growth framework using abstract syntax trees, analysis, and output generation. It covers various rules, symbols, and computations involved in the translation.

Typology: Study notes

Pre 2010

Uploaded on 02/10/2009

koofers-user-jgc
koofers-user-jgc 🇺🇸

10 documents

1 / 37

Toggle sidebar

Related documents


Partial preview of the text

Download Translating L-System Grammar Specifications to Java: A Study of the Growth Framework and more Study notes Electrical and Electronics Engineering in PDF only on Docsity! Translator for L-System Grammar Specifications to the Java Growth Framework Laura Rassbach Nick Dronen Table of Contents 1 Abstract Syntax Tree 2 Analysis 3 Output 1 1 Abstract Syntax Tree ast.lido[1] ≡ RULE Root: Start ::= Secondary END; RULE Second: Secondary LISTOF Lsys END; RULE System: Lsys ::= ’system’ Name ’:’ LsysGrammar ParamAttrList END; RULE Grammar: LsysGrammar ::= Axiom OtherRules END; RULE Others: OtherRules LISTOF OtherRule END; RULE AxiomRule: Axiom ::= ’axiom’ ’->’ RuleExpansion ’;’ END; RULE GrammarRule: OtherRule ::= MoveCallDef ’->’ Conditional RuleExpansion WidthChange ’;’ END; RULE HasCondition: Conditional ::= ’(’ BooleanExpr ’)’ ’:’END; RULE HasChangedWidth: WidthChange ::= ’:’ ’(’ Param ’)’ END; RULE NoCondition: Conditional ::= END; RULE NoChangedWidth: WidthChange ::= END; RULE RuleExp: RuleExpansion LISTOF GrammarExpr END; RULE Params: ParamList LISTOF TopParam END; RULE FirstTwo: StringParamList ::= StringParam ’,’ StringParam ’,’ StrParmList END; RULE FirstTwoOnly: StringParamList ::= StringParam ’,’ StringParam END; RULE StringList: StrParmList LISTOF StringParam END; RULE TopParm: TopParam ::= Param END; RULE MoveDef: MoveCallDef ::= MoveDirDef ’(’ StringParamList ’)’ END; RULE MoveDirDefn: MoveDirDef ::= MoveDirective END; RULE MoveRule: GrammarExpr ::= MoveDirUse ’(’ ParamList ’)’ END; RULE MoveDirUsen: MoveDirUse ::= MoveDirective END; RULE Pop: GrammarExpr ::= ’]’ END; RULE Push: GrammarExpr ::= ’[’ END; RULE BasicMoveRule: GrammarExpr ::= BasicMove ’(’ Param ’,’ Param ’)’ END; RULE AngleRule: GrammarExpr ::= AngleExpr END; RULE PitchCallP: AngleExpr ::= ’&’ ’(’ ParamIdUse ’)’ END; RULE TurnRightP: AngleExpr ::= ’-’ ’(’ ParamIdUse ’)’ END; RULE TurnLeftP: AngleExpr ::= ’+’ ’(’ ParamIdUse ’)’ END; RULE RollRightP: AngleExpr ::= ’/’ ’(’ ParamIdUse ’)’ END; RULE RollLeftP: AngleExpr ::= ’\’ ’(’ ParamIdUse ’)’ END; RULE PitchCallL: AngleExpr ::= ’&’ ’(’ Literal ’)’ END; 2 MoveCall: MoveDirective ’(’ ExprParameterList ’)’ . MoveCallDef: MoveDirective ’(’ StrParameterList ’)’ . BasicMoveCall: BasicMove ’(’ ExprParameter ’,’ ExprParameter ’)’ . PitchCall: ’&’ ’(’ (Name / ContinuousLit) ’)’ . RollLeftCall: ’\’ ’(’ (Name / ContinuousLit) ’)’ . RollRightCall: ’/’ ’(’ (Name / ContinuousLit) ’)’ . TurnRightCall: ’-’ ’(’ (Name / ContinuousLit) ’)’ . TurnLeftCall: ’+’ ’(’ (Name / ContinuousLit) ’)’ . RollHorizontal: ’$’ . Pop: ’[’ . Push: ’]’ . ExprParameterList: ExprParameter ’,’ ( ExprParameter // ’,’ ) . StrParameterList: Name ’,’ Name ’,’ OtherStrParams / Name ’,’ Name . OtherStrParams: (Name // ’,’) . BooleanExpr: ExprParameter ’>’ ExprParameter / ExprParameter ’<’ ExprParameter / ExprParameter ’<=’ ExprParameter / ExprParameter ’>=’ ExprParameter / ExprParameter ’=’ ExprParameter / ’(’ BooleanExpr ’)’ / ’!’ BooleanExpr . ExprParameter: ExprParameter ’+’ MultOrDiv / ExprParameter ’-’ MultOrDiv / MultOrDiv . MultOrDiv: MultOrDiv ’*’ Primary / MultOrDiv ’/’ Primary / Primary . Primary: ’(’ ExprParameter ’)’ / Parameter . Parameter: Name / ContinuousLit . ParamAttrList: ParamAttr* . ParamAttr: Name ’:’ ( ContinuousAttr / DiscreteAttr / TickAttr ) . DiscreteAttr: ’discrete’ ’,’ DiscreteLit ’,’ DiscreteLit ’,’ DiscreteLit ’;’ . ContinuousAttr: ’continuous’ ’,’ VisibleAttr ’,’ ContinuousLit ’,’ ContinuousLit ’,’ ContinuousLit ’,’ DiscreteLit ’;’ . TickAttr: ’ticks’ ’=’ ’(’ ContinuousLit ’,’ ContinuousLit ’)’ ’;’ . 5 DiscreteLit: DiscreteNum / ’-’ DiscreteNum . ContinuousLit: ContinuousNum / DiscreteNum / ’-’ ContinuousNum / ’-’ DiscreteNum . VisibleAttr: ’visible’ / ’non-visible’ . This macro is attached to a product file. Rationale for the AST Design[5] ≡ Criteria and Scores, or Why R AST r4wkz!!1! 1. Different rules for context-sensitive roles (importance: 50) 95 points. All context-sensitive rules are separated, but there is an unresolveable issue with AngleExpr, which plays two roles simultaneously (it defines a class and creates an instance of that class). 2. Meaningful rule and symbol names (importance: 45) 80 points. Our AST is not perfect with respect to this criterion. While some rule names are abbreviated versions of corresponding rules in the concrete grammar, this is necessary because of the number of productions in the concrete grammar. A weakness of the names of rules in our AST is that we don’t follow a single convention for them (e.g. Axiom/AxiomRule vs. RuleExpansion/RuleExp). These variations in convention are not so disruptive as to warrant changing them. 3. Covers the grammar (importance: 35) 100 points! 4. Ease of computation (importance: 35) 90 points. We have introduced a number of additional symbols into the grammar which complicate the tree but make computation much easier. At this point, most computations are made as simple as reasonably possible for this tree. This macro is invoked in definition 17. 6 2 Analysis This file defines signatures for C functions defined in lsys.c and includes type definitions for structs which are used to hold properties of parameters. lsys.h[6] ≡ #ifndef _LSYS_H #define _LSYS_H #include "envmod.h" #include "err.h" Binding customBindParam(Environment ruleEnv, Environment sysEnv, int idn); #endif This macro is attached to a product file. This file is used to create a custom binding operator for Lsystem-scope parameters (since they must be bound in a particular environment, but only if they are not already bound). lsys.c[7] ≡ #include "lsys.h" #include "err.h" Binding customBindParam(Environment ruleEnv, Environment sysEnv, int idn) { Binding binding = BindingInEnv(ruleEnv, idn); if (binding == NoBinding) { binding = BindInScope(sysEnv, idn); } return binding; } This macro is attached to a product file. lsys.head[8] ≡ #include "lsys.h" This macro is attached to a product file. names.pdl[9] ≡ /*Properties of grammar symbols*/ NumArgs: int; /*Properties of parameters*/ IsContinuous: int; IsAttributed: int; IsTicked: int; IsVisible: int; /* usage properties */ UsedAngle: int; 7 END; SYMBOL ParamAttr INHERITS IdUseEnv COMPUTE SYNT.Sym = TERM; /* only define attributes for parameters that have been defined in the grammar */ IF(EQ(KeyInScope(INCLUDING Lsys.Env, SYNT.Sym), NoKey), message(ERROR, CatStrInd("Parameter is not defined: ", SYNT.Sym), 0, COORDREF)) <- INCLUDING Lsys.Done; END; SYMBOL TopParam COMPUTE SYNT.Count = 1; END; SYMBOL MoveDirDef INHERITS IdUseEnv COMPUTE /* a symbol may only appear once on the left-hand side of an "->" */ SYNT.Bind = IF(NOT(EQ(BindingInEnv(INCLUDING AnyScope.Env, SYNT.Sym),NoBinding)), ORDER( message(ERROR,CatStrInd("Symbol defined multiple times: ", SYNT.Sym),0,COORDREF), NoBinding), BindInScope(INCLUDING Lsys.Env, SYNT.Sym)); SYNT.Sym = TERM; END; SYMBOL MoveDirUse INHERITS IdUseEnv COMPUTE SYNT.Sym = TERM; END; SYMBOL GrammarExpr COMPUTE SYNT.whichSet = 0; SYNT.typeKey = NoKey; END; /* counter for "function" parameters */ ATTR Count: int; /* sum of counted arguments */ ATTR ArgCount: int; /* whether it visibility on a continuous parameter is "true" or not */ ATTR isVis: int; 10 /* primitive values for literals */ ATTR IValue: int; ATTR FValue: double; /* used to identify parameter usage */ ATTR whichSet: int; ATTR typeKey: DefTableKey; ATTR curpos: CoordPtr; /* ensures that parameters are given attributes in textual order */ CHAIN AttrChain: VOID; RULE System: Lsys ::= ’system’ Name ’:’ LsysGrammar ParamAttrList COMPUTE CHAINSTART ParamAttrList.AttrChain = "go"; LsysGrammar.PropsDone = ParamAttrList.AttrChain; BindInScope(Lsys.Env, iterSym); Lsys.used = SetUsedAxiom(KeyInEnv(Lsys.Env, iterSym), 1, 2); IF(NOT(GetIsAttributed(KeyInEnv(Lsys.Env, iterSym), 0)), message(ERROR, "Implicit parameter \"Number of iterations\" has no attributes defined.", 0, COORDREF)) <- LsysGrammar.PropsDone; Lsys.Done = LsysGrammar.Done; END; RULE Grammar: LsysGrammar ::= Axiom OtherRules COMPUTE LsysGrammar.Done = OtherRules.Done; END; RULE Others: OtherRules LISTOF OtherRule COMPUTE OtherRules.Done = CONSTITUENTS MoveCallDef.Done; END; RULE AxiomRule: Axiom ::= ’axiom’ ’->’ RuleExpansion ’;’ COMPUTE RuleExpansion.whichSet = 2; RuleExpansion.typeKey = NoKey; END; RULE GrammarRule: OtherRule ::= MoveCallDef ’->’ Conditional RuleExpansion WidthChange ’;’ COMPUTE RuleExpansion.whichSet = 1; RuleExpansion.typeKey = MoveCallDef.typeKey; OtherRule.whichSet = RuleExpansion.whichSet; OtherRule.typeKey = RuleExpansion.typeKey; END; 11 RULE MoveDef: MoveCallDef ::= MoveDirDef ’(’ StringParamList ’)’ COMPUTE MoveCallDef.Done = ResetNumArgs(MoveDirDef.Key, CONSTITUENTS StringParam.Count WITH(int, ADD, IDENTICAL, ZERO)); MoveCallDef.typeKey = MoveDirDef.Key; END; RULE MoveRule: GrammarExpr ::= MoveDirUse ’(’ ParamList ’)’ COMPUTE MoveDirUse.ArgCount = CONSTITUENTS TopParam.Count WITH(int, ADD, IDENTICAL, ZERO) <- INCLUDING LsysGrammar.Done; IF(EQ(GetNumArgs(MoveDirUse.Key, NEG(1)), NEG(1)), message(ERROR, CatStrInd("Undefined symbol: ", MoveDirUse.Sym), 0, COORDREF), IF(NOT(EQ(GetNumArgs(MoveDirUse.Key, NEG(1)), MoveDirUse.ArgCount)), message(ERROR, CatStrInd("Bad argument count in call to symbol ", MoveDirUse.Sym), 0, COORDREF))); GrammarExpr.whichSet = INCLUDING RuleExpansion.whichSet; GrammarExpr.typeKey = INCLUDING RuleExpansion.typeKey; END; RULE BasicMoveRule: GrammarExpr ::= BasicMove ’(’ Param ’,’ Param ’)’ COMPUTE GrammarExpr.whichSet = INCLUDING RuleExpansion.whichSet; GrammarExpr.typeKey = INCLUDING RuleExpansion.typeKey; END; RULE AngleRule: GrammarExpr ::= AngleExpr COMPUTE GrammarExpr.typeKey = AngleExpr.typeKey; END; RULE PitchCallP: AngleExpr ::= ’&’ ’(’ ParamIdUse ’)’ COMPUTE AngleExpr.typeKey = ptchKey; END; RULE TurnRightP: AngleExpr ::= ’-’ ’(’ ParamIdUse ’)’ COMPUTE AngleExpr.typeKey = trKey; END; RULE TurnLeftP: AngleExpr ::= ’+’ ’(’ ParamIdUse ’)’ COMPUTE AngleExpr.typeKey = tlKey; END; RULE RollRightP: AngleExpr ::= ’/’ ’(’ ParamIdUse ’)’ COMPUTE AngleExpr.typeKey = rrKey; END; RULE RollLeftP: AngleExpr ::= ’\’ ’(’ ParamIdUse ’)’ COMPUTE 12 RULE DiscLiteral: Literal ::= DiscreteNum COMPUTE Literal.IValue = DiscreteNum; Literal.FValue = DiscreteNum; END; RULE NContLiteral: Literal ::= ’-’ ContinuousNum COMPUTE Literal.FValue = NEG(atof(StringTable(ContinuousNum))); Literal.IValue = NEG(1); END; RULE NDiscLiteral: Literal ::= ’-’ DiscreteNum COMPUTE Literal.IValue = NEG(DiscreteNum); Literal.FValue = NEG(DiscreteNum); END; This macro is attached to a product file. Our source program analyzer does name analysis and most of the needed error checking on our input. We have two different kinds of variables to store in the definition table: grammar symbols (which are similar to function definitions in some ways) and parameters. The appearance of a grammar symbol (like A or Trunk) on the left hand side of an arrow is considered a defining occurrence, and only one defining occurrence of each grammar symbol is allowed. The scope of the symbol is the entire ”Lsys”scope. Because of this, left-hand sides of the arrows must be evaluated before any right-hand sides. In addition, like functions, grammar symbols have some number of parameters (at least two). Any use of a grammar symbol on the right hand side of an arrow must have the same number of parameters as when it was defined. However, since our specification language has no types, we chose to simply write this computation rather than using the built-in function-checking computations. The only property of a grammar symbol is this number of arguments count. Our analyzer checks for and reports the following errors: A grammar symbol is defined multiple times A grammar symbol is used but never defined A grammar symbol is used with the wrong number of parameters Our other variable type is a parameter. Here the scoping rules are more complicated. Any instance of a parameter in a rule context (on either side of the arrow) is considered a defining occurrence. If it is on the left-hand side of the arrow, it is defined for the scope of the rule. If it is on the right-hand side and not already defined, it is defined in the ”Lsys”scope (not the rule scope). This required us to write a custom C binding function. In addition, after the rules have been defined a list of details about each parameter appears in the spec- ification. Parameter names here are considered applied occurrences, and are only valid if they have been defined in the ”Lsys”scope by the grammar. These properties must be defined for each parameter exactly once. If a ”ticks”property is given, the parameter must previously have been given a ”continuous”property with ”visible”true. The final analysis done on parameters is to detect which Symbol classes in the output will need access to each parameter. Three types of symbols (axiom, move, and angle) are tracked; if only one symbol needs a parameter then its key is also needed and stored (with the exception of the axiom, since there is only one axiom). Finally, a known constant parameter called ”Number of iterations”is defined in the ”Lsys”scope automatically, and is known to be used in the axiom symbol. The following errors and potential errors are detected for parameters (each error is listed with the file or files in the tests directory that demonstrates it): An error is issued if no attributes are defined for some ”Lsys”scope parameter (including ”Number of itera- tions”) -NoUsedAttr 15 -NoIterAttr An error is issued if attributes are defined for a parameter that does not exist in the ”Lsys”scope -UndefParam -WrongScopeParam An error is issued if the user attempts to give a parameter properties (continuous or discrete) or ticks multiple times -MultProp An error is issued if the user attempts to give ”ticks”to a parameter not previously declared continuous and visible -BadTicks An error is issued if a system-level parameter is used by multiple types of symbols (angle, move, or axiom) -MultUseType Errors are issued if the given ”min”, ”max”, and ”initial values”of a parameter do not make sense, such as if ”min”is greater than ”max” -BadParamVals Additionally, a complete, error-free test case (that generates all the L-Systems currently hand-implemented in Growth) is contained in the file tests/fulltest With the exception of binding certain parameters, all of these computations and checks use the standard name analysis module with C scoping rules and standard LIDO computations (primarily IF statements to detect errors). 16 3 Output output.pdl[11] ≡ /* ptg node that is the value of a parameter */ PtgText: PTGNode; /* ptg node that is the definition of a parameter */ PtgParamDef: PTGNode; /* ptg node that is the "ticks" of a parameter */ PtgTicksDef: PTGNode; /* ptg node that is the name of a parameter */ PtgName: PTGNode; /* ptg nodes used to combine declarations for several parameters */ PtgParamDefs: PTGNode; PtgTicksDefs: PTGNode; PtgNames: PTGNode; /* iteratively built list that has exactly one instance of each parameter */ PtgParameterSymbols: PTGNode; AddedToParameterSymbols: int; "ptg_gen.h" This macro is attached to a product file. output.head[12] ≡ #include <stdlib.h> #include "output.h" This macro is attached to a product file. output.h[13] ≡ #ifndef __OUTPUT_H #define __OUTPUT_H char *makePath(char *systemName, char *symbolName); char *makeNameWithInt(char *systemName, char *firstPart, int secondPart); char *makeNameWithStr(char *systemName, char *firstPart, char *secondPart); #endif This macro is attached to a product file. output.c[14] ≡ #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include "output.h" 17 PTGClassDec( SYNT.ptgSymbolName, PTGAsIs("ChangeDirectionSymbol"), PTGAngleBodyNoParm( SYNT.paramTextParm, SYNT.ptgSymbolName, SYNT.ptgAction, SYNT.neg ) ) ), PTGSourceFile( PTGPackage(INCLUDING Lsys.ptgSymbolName), PTGImport(), PTGClassDec( SYNT.ptgSymbolName, IF(SYNT.paramLocal, PTGAsIs("ChangeDirectionSymbol"), PTGSystemSymbol(INCLUDING Lsys.ptgSymbolName, PTGAsIs("ChangeDirection")) ), PTGAngleBodyParm(SYNT.ptgParams, SYNT.ptgAction, SYNT.neg, SYNT.paramTextParm) ) ) ); PTGOutFile(StringTable(SYNT.outputFile), SYNT.ptgClass); END; /* the code for a symbol within a getExpansion() method */ ATTR ptg: PTGNode; /* declarations & initializations of local variables in a MoveForward symbol */ ATTR ptgDecs: PTGNode; ATTR ptgParams: PTGNode; ATTR ptgCode: PTGNode; /* ptg node that is the entire class of a Symbol that declares a class */ ATTR ptgClass: PTGNode; /* ptg node that is the name of a symbol */ ATTR ptgSymbolName: PTGNode; /* string table index for the name of a symbol */ ATTR symbolName: int; /* string table index for the name of a top-level Lsystem */ ATTR systemName: int; /* file where a symbol will be output; based on the above */ ATTR outputFile: int; /* Lsystem name that will be shown to the user */ ATTR shownName: int; ATTR ptgShownName: PTGNode; /* ptg node that is the name of a parameter */ 20 ATTR paramName: PTGNode; /* ptg nodes for the top angle and top move classes, generated in Lsys */ ATTR ptgTopAngle: PTGNode; ATTR ptgTopMove: PTGNode; /* keys for information needed by the top angle, move, and axiom classes */ ATTR topAngleKey: DefTableKey; ATTR topMoveKey: DefTableKey; ATTR axiomKey: DefTableKey; /* attributes used to pass information to the AngleExpr symbol computation */ ATTR ptgAction: PTGNode; ATTR paramText: PTGNode; ATTR neg: PTGNode; ATTR paramSym: int; ATTR paramKey: DefTableKey; ATTR name: int; /* attributes for referencing a parameter in an AngleExpr computation */ ATTR paramTextCall: PTGNode; ATTR paramTextParm: PTGNode; /* whether a parameter is a system parameter, and whether it is defined in the local context */ ATTR paramLocal: int; ATTR isNonSystem: int; /* stores the expansion method of a MoveForward symbol */ ATTR ptgExpansion: PTGNode; /* key for where a parameter is defined */ ATTR topKey: DefTableKey; /* temporary ptg nodes used while generating the AxiomSymbol class */ ATTR ptgIters: PTGNode; ATTR ptgParamSymbols: PTGNode; ATTR ptgHelp: PTGNode; /* default value for creating a new MoveForwardSymbol */ ATTR ptgDefault: PTGNode; /* assignment statement for the index of an Lsystem in the factory */ ATTR ptgAssignIndex: PTGNode; /* counter for Lsystems; gives correct index to each */ CHAIN lsysCount: int; RULE Root: Start ::= Secondary COMPUTE Start.factoryIndex = 0; Start.initDone = ORDER( ResetPtgText(wc2Key, PTGAsIs("Options.getTwoBranchWidthContraction()")), ResetPtgText(wc3Key, PTGAsIs("Options.getThreeBranchWidthContraction()")), 21 ResetPtgText(wcKey, PTGAsIs("getWidthContraction()"))); CHAINSTART Secondary.lsysCount = 0; PTGOutFile("generator/LSystemFactory.java", PTGSourceFile( PTGFactoryPackage(), PTGSeq( PTGFactoryImportTop(), PTGSeq( CONSTITUENTS Lsys.ptgSymbolName WITH (PTGNode, PTGSeq, PTGFactoryImportGenerator, PTGNull), PTGFactoryImportGui() ) ), PTGFactoryBody( CONSTITUENTS Lsys.ptgAssignIndex WITH (PTGNode, PTGSeq, IDENTICAL, PTGNull), PTGFactorySystemNames( CONSTITUENTS Lsys.ptgShownName WITH (PTGNode, PTGCommaSeq, IDENTICAL, PTGNull) ), PTGFactoryGetAxiomSymbol( CONSTITUENTS Lsys.ptgSymbolName WITH (PTGNode, PTGSeq, PTGFactoryCaseReturn, PTGNull) ) ) ) ); END; RULE System: Lsys ::= ’system’ Name ’:’ LsysGrammar ParamAttrList COMPUTE Lsys.systemName = GenerateName("System"); Lsys.ptgSymbolName = PTGId(Lsys.systemName); Lsys.topAngleKey = NewKey(); Lsys.topMoveKey = NewKey(); Lsys.axiomKey = NewKey(); Lsys.shownName = Name; Lsys.ptgShownName = PTGId(Name); Lsys.lsysCount = ADD(Lsys.lsysCount, 1); Lsys.ptgAssignIndex = PTGFactoryAvailableSystem( Lsys.ptgSymbolName, Lsys.lsysCount ); Lsys.ptgTopAngle = IF (NOT(EQ(GetPtgParamDefs(Lsys.topAngleKey, PTGNULL), PTGNULL)), PTGTopAngleClass(PTGPackage(Lsys.ptgSymbolName), PTGImport(), 22 ResetPtgParameterSymbols(INCLUDING Lsys.axiomKey, PTGCommaSeq(GetPtgParameterSymbols(INCLUDING Lsys.axiomKey, PTGNULL), PTGConstruct(MoveCallDef.ptgSymbolName, CONSTITUENTS StringParam.ptgDefault WITH(PTGNode, PTGCommaSeq, IDENTICAL, PTGNull)))), ResetAddedToParameterSymbols(INCLUDING Lsys.topMoveKey, 1))), ResetPtgParameterSymbols(INCLUDING Lsys.axiomKey, PTGCommaSeq(GetPtgParameterSymbols(INCLUDING Lsys.axiomKey, PTGNULL), PTGConstruct(MoveCallDef.ptgSymbolName, CONSTITUENTS StringParam.ptgDefault WITH(PTGNode, PTGCommaSeq, IDENTICAL, PTGNull))))) <- INCLUDING Lsys.topsDone; PTGOutFile( makePath( StringTable(INCLUDING Lsys.systemName), makeNameWithStr( StringTable(INCLUDING Lsys.systemName), StringTable(MoveCallDef.name), "") ), OtherRule.ptgClass ); END; RULE HasCondition: Conditional ::= ’(’ BooleanExpr ’)’ ’:’ COMPUTE Conditional.ptg = PTGExpansionMeth(PTGConditionSymb( BooleanExpr.ptg, Conditional.ptgExpansion)); END; RULE HasChangedWidth: WidthChange ::= ’:’ ’(’ Param ’)’ COMPUTE WidthChange.ptg = PTGWidthMeth(Param.ptg); END; RULE NoCondition: Conditional ::= COMPUTE Conditional.ptg = PTGExpansionMeth(Conditional.ptgExpansion); END; RULE NoChangedWidth: WidthChange ::= COMPUTE WidthChange.ptg = PTGNULL; END; RULE RuleExp: RuleExpansion LISTOF GrammarExpr COMPUTE RuleExpansion.ptgExpansion = PTGSymbArray(CONSTITUENTS GrammarExpr.ptg WITH (PTGNode, PTGCommaSeq, IDENTICAL, PTGNull)); END; RULE FirstTwo: StringParamList ::= StringParam ’,’ StringParam ’,’ StrParmList COMPUTE StringParamList.PTGSet = ORDER(ResetPtgText(StringParam[1].Key, PTGAsIs("length")), ResetPtgText(StringParam[2].Key, PTGAsIs("width"))); 25 /* this guy’s ptg is the constructor of the symbol being defined and any needed var decs */ StringParamList.ptg = PTGMoveConstructor(StrParmList.ptgDecs, INCLUDING MoveCallDef.ptgSymbolName, StrParmList.ptgParams, StrParmList.ptgCode); END; RULE FirstTwoOnly: StringParamList ::= StringParam ’,’ StringParam COMPUTE StringParamList.PTGSet = ORDER(ResetPtgText(StringParam[1].Key, PTGAsIs("length")), ResetPtgText(StringParam[2].Key, PTGAsIs("width"))); StringParamList.ptg = PTGMoveConstructor(PTGNULL, INCLUDING MoveCallDef.ptgSymbolName, PTGNULL, PTGNULL); END; RULE StringList: StrParmList LISTOF StringParam COMPUTE StrParmList.ptgDecs = CONSTITUENTS StringParam.ptg WITH(PTGNode, PTGSemiSeq, PTGDoubleVarDec, PTGNull); StrParmList.ptgParams = CONSTITUENTS StringParam.ptg WITH(PTGNode, PTGCommaSeq, PTGDoubleVarDec, PTGNull); StrParmList.ptgCode = CONSTITUENTS StringParam.ptg WITH(PTGNode, PTGSemiSeq, PTGVarAssign, PTGNull); END; RULE TopParm: TopParam ::= Param COMPUTE TopParam.ptg = Param.ptg; END; RULE MoveDef: MoveCallDef ::= MoveDirDef ’(’ StringParamList ’)’ COMPUTE MoveCallDef.name = MoveDirDef.Sym; MoveCallDef.ptgSymbolName = PTGSystemSymbol(INCLUDING Lsys.ptgSymbolName, PTGId(MoveDirDef.Sym)); MoveCallDef.textSet = ResetPtgName(MoveDirDef.Key, MoveCallDef.ptgSymbolName); MoveCallDef.ptg = StringParamList.ptg; END; RULE MoveRule: GrammarExpr ::= MoveDirUse ’(’ ParamList ’)’ COMPUTE GrammarExpr.ptg = PTGConstruct(GetPtgName(MoveDirUse.Key, PTGNULL), CONSTITUENTS TopParam.ptg WITH(PTGNode, PTGCommaSeq, IDENTICAL, PTGNull)) <- INCLUDING Lsys.textSet; END; RULE Pop: GrammarExpr ::= ’]’ COMPUTE GrammarExpr.ptg = PTGConstruct(PTGAsIs("PopSymbol"), PTGNULL); END; RULE Push: GrammarExpr ::= ’[’ 26 COMPUTE GrammarExpr.ptg = PTGConstruct(PTGAsIs("PushSymbol"), PTGNULL); END; RULE BasicMoveRule: GrammarExpr ::= BasicMove ’(’ Param ’,’ Param ’)’ COMPUTE GrammarExpr.ptg = PTGBaseMove(Param[1].ptg, Param[2].ptg); END; RULE AngleRule: GrammarExpr ::= AngleExpr COMPUTE GrammarExpr.ptg = AngleExpr.ptg; END; RULE PitchCallP: AngleExpr ::= ’&’ ’(’ ParamIdUse ’)’ COMPUTE AngleExpr.paramKey = ParamIdUse.Key; AngleExpr.paramSym = ParamIdUse.Sym; AngleExpr.name = MakeName("Pitch"); AngleExpr.ptgAction = PTGAsIs("Pitch"); END; RULE TurnRightP: AngleExpr ::= ’-’ ’(’ ParamIdUse ’)’ COMPUTE AngleExpr.paramKey = ParamIdUse.Key; AngleExpr.paramSym = ParamIdUse.Sym; AngleExpr.name = MakeName("TurnRight"); AngleExpr.ptgAction = PTGAsIs("Turn"); AngleExpr.neg = PTGAsIs("-"); END; RULE TurnLeftP: AngleExpr ::= ’+’ ’(’ ParamIdUse ’)’ COMPUTE AngleExpr.paramKey = ParamIdUse.Key; AngleExpr.paramSym = ParamIdUse.Sym; AngleExpr.name = MakeName("TurnLeft"); AngleExpr.ptgAction = PTGAsIs("Turn"); END; RULE RollRightP: AngleExpr ::= ’/’ ’(’ ParamIdUse ’)’ COMPUTE AngleExpr.paramKey = ParamIdUse.Key; AngleExpr.paramSym = ParamIdUse.Sym; AngleExpr.name = MakeName("RollRight"); AngleExpr.ptgAction = PTGAsIs("Roll"); END; RULE RollLeftP: AngleExpr ::= ’\’ ’(’ ParamIdUse ’)’ COMPUTE AngleExpr.paramKey = ParamIdUse.Key; AngleExpr.paramSym = ParamIdUse.Sym; AngleExpr.name = MakeName("RollLeft"); AngleExpr.ptgAction = PTGAsIs("Roll"); AngleExpr.neg = PTGAsIs("-"); END; RULE PitchCallL: AngleExpr ::= ’&’ ’(’ Literal ’)’ COMPUTE 27 IF(GetUsedAxiom(.paramKey, 0), INCLUDING Lsys.axiomKey, NoKey))) <- INCLUDING Lsys.topsDone; TickAttr.PtgSet = ResetPtgTicksDef(.paramKey, PTGTickParamDef(GetPtgName(.paramKey, PTGNULL), Literal[1].FValue, Literal[2].FValue)) <- INCLUDING ParamAttrList.PtgDefsDone; TickAttr.textSet = IF(NOT(EQ(.topKey, NoKey)), ResetPtgTicksDefs(.topKey, PTGSeq(GetPtgTicksDefs(.topKey, PTGNULL), GetPtgTicksDef(.paramKey, PTGNULL)))) <- TickAttr.PtgSet; END; RULE VisAttr: VisibleAttr ::= ’visible’ COMPUTE VisibleAttr.ptg = PTGAsIs("Shown"); END; RULE NonVisAttr: VisibleAttr ::= ’non-visible’ COMPUTE VisibleAttr.ptg = PTGAsIs("Hidden"); END; RULE Add: Param ::= Param ’+’ Param COMPUTE Param[1].ptg = PTGBinaryOperation( Param[2].ptg, "+", Param[3].ptg); END; RULE Subtract: Param ::= Param ’-’ Param COMPUTE Param[1].ptg = PTGBinaryOperation( Param[2].ptg, "-", Param[3].ptg); END; RULE Multiply: Param ::= Param ’*’ Param COMPUTE Param[1].ptg = PTGBinaryOperation( Param[2].ptg, "*", Param[3].ptg); END; RULE Divide: Param ::= Param ’/’ Param COMPUTE Param[1].ptg = PTGBinaryOperation( Param[2].ptg, "/", Param[3].ptg); END; RULE Greater: BooleanExpr ::= Param ’>’ Param COMPUTE BooleanExpr.ptg = PTGBinaryBooleanOperation( Param[1].ptg, ">", Param[2].ptg); END; RULE Less: BooleanExpr ::= Param ’<’ Param COMPUTE 30 BooleanExpr.ptg = PTGBinaryBooleanOperation( Param[1].ptg, "<", Param[2].ptg); END; RULE GreaterEq: BooleanExpr ::= Param ’>=’ Param COMPUTE BooleanExpr.ptg = PTGBinaryBooleanOperation( Param[1].ptg, ">=", Param[2].ptg); END; RULE LessEq: BooleanExpr ::= Param ’<=’ Param COMPUTE BooleanExpr.ptg = PTGBinaryBooleanOperation( Param[1].ptg, "<=", Param[2].ptg); END; RULE Equal: BooleanExpr ::= Param ’=’ Param COMPUTE BooleanExpr.ptg = PTGBinaryBooleanOperation( Param[1].ptg, "==", Param[2].ptg); END; RULE Not: BooleanExpr ::= ’!’ BooleanExpr COMPUTE BooleanExpr[1].ptg = PTGUnaryBooleanOperation( "!", BooleanExpr[2].ptg); END; RULE Number: Param ::= Literal COMPUTE Param.ptg = Literal.ptg; END; RULE Var: Param ::= ParamIdUse COMPUTE Param.ptg = ParamIdUse.ptg; END; RULE ParmIdUse: ParamIdUse ::= Name COMPUTE ParamIdUse.ptg = GetPtgText(ParamIdUse.Key, PTGNULL) <- INCLUDING Lsys.textSet; END; RULE String: StringParam ::= Name COMPUTE StringParam.textSet = IF(EQ(GetPtgText(StringParam.Key, PTGNULL), PTGNULL), ResetPtgText(StringParam.Key, PTGId(GenerateName("parm")))) <- INCLUDING StringParamList.PTGSet; StringParam.ptg = GetPtgText(StringParam.Key, PTGNULL) <- StringParam.textSet; StringParam.ptgDefault = PTGNumb(0); END; RULE ParamAttrs: ParamAttrList LISTOF ParamAttr COMPUTE ParamAttrList.PtgDefsDone = "bleh" <- (CONSTITUENTS ContinuousAttr.PtgSet, CONSTITUENTS DiscreteAttr.PtgSet); 31 ParamAttrList.textSet = "bleh" <- (CONSTITUENTS ContinuousAttr.textSet, CONSTITUENTS DiscreteAttr.textSet, CONSTITUENTS TickAttr.textSet); END; RULE ContLiteral: Literal ::= ContinuousNum COMPUTE Literal.ptg = PTGContLit(Literal.FValue); END; RULE DiscLiteral: Literal ::= DiscreteNum COMPUTE Literal.ptg = PTGNumb(Literal.IValue); END; RULE NContLiteral: Literal ::= ’-’ ContinuousNum COMPUTE Literal.ptg = PTGContLit(Literal.FValue); END; RULE NDiscLiteral: Literal ::= ’-’ DiscreteNum COMPUTE Literal.ptg = PTGNumb(Literal.IValue); END; This macro is attached to a product file. lsys.ptg[16] ≡ SystemSymbol: $ $ "Symbol" Construct: "new " $ "(" $ ")" Package: "package generator.symbols." $ ";\n\n" Import: "import generator.symbols.*;\n" "import generator.*;\n" "import gui.Options;\n" SourceFile: $ /* package statement */ $ /* import statements */ "\n" $ /* body of file */ AxiomBody: "public class " $ " extends AxiomSymbol {\n" $ /* parameter definitions */ $ /* axiom expansion */ $ /* getIterations() method */ $ /* getParameterSymbols() method */ $ /* getHelpMapID() method */ "}\n" Iterations: "protected int getIterations()\n{\nreturn " $ ";\n}\n" ParamSymbols: "public Symbol[] getParameterSymbols()\n{\nreturn new Symbol[] {" $ "};\n}\n" HelpMeth: "public String getHelpMapID()\n{\nreturn" $ ";\n}\n" MoveConstructor: $ "\npublic " $ "(double len, double wid" {", " } $ 32 "}\n" FactoryCaseReturn: " case " $1 ":\n" " return new " $1 "AxiomSymbol();\n" SemiSeq: $1 ";" $2 ";" ContLit: $double This macro is attached to a product file. This specification generates as output Java Symbol classes which are fully compatible with Growth. It expects to be run in the top-level Growth directory (with a generator and generator/symbols directory defined in the current directory). Although it is not necesary to do so, it is recommended that the symbols directory be emptied of all subdirectories (system-specific symbols) before running this code. This specification assumes that there is only one input file, which contains all the desired L-Systems in the final product. Symbols will be generated correctly whether or not this last constraint is met; but the generated LSystemFactory class will be incorrect. Any two acceptable input specifications may be concatenated to create another acceptable input specification. This specification outputs a large number of files in subdirectories, which are required by Growth to properly display the L-System. Here is a listing of the files created: -generator/LSystemFactory.java For each L-System: -a subdirectory generator/symbols/SystemX, where X is a unique integer for each L-System -generator/symbols/SystemX/SystemXAxiomSymbol.java -one file for each rule construction in the grammar. If the rule is of the form Name(...) ->..., the name of the file is generator/symbols/SystemX/SystemXNameSymbol.java -one file for each angle (’&’, ’+’, ’-’, ’/’, ’\’) production with a unique system-level pa- rameter in the production. That is, &(bob) and &(fred) would generate two distinct files, but two instances of &(bob) would still generate only one. These files are named generator/symbols/SystemX/SystemX<AngleType>YSymbol.java, where <AngleType> is one of Pitch, TurnLeft, TurnRight, RollLeft, and RollRight, and Y is an integer unique to the parameter to the symbol. -one file for each angle type production which does not take a system-level parameter. These files are named generator/symbols/SystemX/SystemXNoParam<AngleType>Symbol.java, where <AngleType> is defined as above. -optionally, one file named generator/symbols/SystemX/SystemXMoveForwardSymbol.java, which acts as a superclass to all the MoveForward-type symbols in the L-System. -optionally, one file named generator/symbols/SystemX/SystemXChangeDirectionSymbol.java, which acts as a superclass to some of the ChangeDirection-type symbols in the L-System. Each generated java file defines a single class. The LSystemFactory class is a simple factory which references the Growth Options object (defined by the framework) and, based on the L-System selected there, returns the AxiomSymbol from that system. It also defines a String array of L-System names used to display the L-System choices to the user. The index of this array is the same as the integer in Options which selects the L-System. Most Symbol classes need to declare, initialize, and return (in getParameters()) some number of system- level parameters. Where this will occur for each parameter is determined by the ”usage”computations in names.fw and referenced here. The code for these operations is built up iteratively in the ContinuousAttr, DiscreteAttr, and TicksAttr grammar symbols. These symbols were chosen since exactly one ContinuousAttr or DiscreteAttr is defined for each system-level parameter. Furthermore, all of the information needed to 35 generate the appropriate code is easily accessable from these symbols. The code is stored as a property of the symbol which will define each parameter in the final code. The AxiomSymbol class is required to implement a number of methods. Firstly, it is known to define at least the ”Number of iterations”parameter, and possibly some others, and these must be included. Second, it must define a getExpansion() method. This method simply returns the comma-separated list of GrammarExpr ptg attributes on the right-hand side of the rule. The GrammarExpr ptg attributes are assigned so that they match the needed code for this method. Next, it needs a getIterations() method. This method always simply returns the value of the implicitly defined ”Number of iterations”parameter (and is why this parameter is needed in every L-System). Next, it defines a getParameterSymbols() method. This method returns instances of Symbol classes containing parameter definitions (either locally or in a superclass) such that each system-level parameter is covered exactly once. Since the AxiomSymbol is known to have a ”Number of iterations”parameter, it is always included. The other Symbols are added to the list in a manner similar to the parameter definitions, in the rules where those Symbols are defined. Finally, the AxiomSymbol is required to implement the getHelpMapID() method, which allows the Growth system to display context-sensitive help. This is simply a String, currently chosen as the user-displayed name of the L-System. One class is generated for each rule in the grammar. In most cases, these Symbol classes will extend a generated ”MoveForward”class so that they can access their parameters. This is because if any parameters are used by multiple MoveForwardSymbols in an L-System, all parameters used by MoveForwardSymbols will be defined in a single superclass. This abstract superclass defines, initializes, and returns the generated list of parameters. Defining parameters in the superclass greatly simplifies the logic for whether a Symbol class must be included in the list of ParameterSymbols for the AxiomSymbol, and is mostly consistent with the choices made by a human translating from specification to Growth code. If no multiply-used MoveFor- wardSymbol parameters exist, then no SystemXMoveForwardSymbol will be generated and the appropriate system-level parameters will be defined in the individual MoveForwardSymbols. The getExpansion() method of a MoveForwardSymbol is generated from the ptg attributes of the GrammarExprs on the right hand side. If the particular symbol contains an ”if”production (a boolean expression in parentheses, followed by a colon, as the first thing on the right-hand side of the rule defining the symbol), this list of symbols is placed inside an if statement so that it is returned only if the statement is true. Otherwise the current symbol is returned. Finally, if the particular symbol contains a width change production (a colon followed by some expression in parentheses at the end of the rule defining the symbol), the getWidthContraction() method is overridden for the MoveForwardSymbol, and now returns the expression given in the spec. For each angle production on the right hand side of a given rule, a class is produced. In some cases a class will be output multiple times, but this presents no difficulty since the files have the same name and contents, and no errors are reported when a file is overwritten. All angle symbols must implement the getAction() method, which returns an Action whose type is defined by the type of angle symbol being produced, and which takes a single parameter in the constructor. Two decisions must be made before the class can be output: whether the production takes a system-level parameter, and whether the needed system-level parameter is defined locally or in a superclass. If the production takes no system-level parameters, the generated class name will be SystemXNoParam<AngleType>Symbol. It will extend ChangeDirectionSymbol and define a constructor taking a single argument of type double. This argument will be saved, and passed as the parameter to the Action created in getAction(). The other two cases both require a system-level parameter. If the parameter is defined locally, the class will extend ChangeDirectionSymbol and have the appropriate parameter definition (described above). If it is defined in a superclass, the class will extend SystemXChangeDirectionSymbol and will not need to do anything with the parameters. In both cases, the class will use the value of the parameter as the argument to the Action constructor in getAction. A SystemXChangeDirectionSymbol will only be output if at least one angle symbol has a non-locally-defined system-level parameter. It is a simple abstract class that simply defines, initializes, and returns a set of parameters. All files are created and output using PTG. Several quite specific PTG skeletons are defined for the various types of classes which need to be output. This is a big win, since the classes are nearly identical with the exception of a few small pieces. This allows us to use only a quite small number of parameters and PTG calls to produce all the (many) files generated, although the tradeoff is a more complicated ptg file. 36 Doc.txt[17] ≡ Rationale for the AST Design[5] This macro is attached to a non-product file. 37
Docsity logo



Copyright © 2024 Ladybird Srl - Via Leonardo da Vinci 16, 10126, Torino, Italy - VAT 10816460017 - All rights reserved