User:Scott Parlane/DesignStudy
From CSSEMediaWiki
(Difference between revisions)
m |
|||
Line 33: | Line 33: | ||
* Code parsing has an inherent requirement for a [[Switch statement smell]]. I have placed all of the switch statements in the parsers. This prevents the need for switch statements in classes, or any later part of the processing. | * Code parsing has an inherent requirement for a [[Switch statement smell]]. I have placed all of the switch statements in the parsers. This prevents the need for switch statements in classes, or any later part of the processing. | ||
* Overriding the code generation in each submodule, and having a single function definition that generates the code helps to [[Avoid downcasting]]. | * Overriding the code generation in each submodule, and having a single function definition that generates the code helps to [[Avoid downcasting]]. | ||
− | * In the parsing the code [[Avoid side effects]] gives the global module a nextToken() and currToken() function, because most of the time the current token is required again, and storing it as a local variable would not work. | + | * In the parsing the code [[Avoid side effects]] gives the global module a nextToken() and currToken() function, because most of the time the current token is required again, and storing it as a local variable would not work. Having nextToken() return anything does violate [[Keep accessors and mutators seperate]] however the benefit of not requiring the call to nextToken() then currToken() is worth this. |
− | * [[Big design up front]] is used to for this project, because the language as a whole needs to be designed before a parser can be started. | + | * [[Big design up front]] is used to for this project, because the language as a whole needs to be designed before a parser can be started. This is only the overall design however, the parser, AST storage, and code generation as designed as required throughout the project. |
* [[Don't expose mutable attributes]] is applied, all classes provide getter and setter methods as required to access their internals. Further, [[Getters and setters]] rule for good design, version 2 is used. However in some places, especially with regards to iterators for maps. | * [[Don't expose mutable attributes]] is applied, all classes provide getter and setter methods as required to access their internals. Further, [[Getters and setters]] rule for good design, version 2 is used. However in some places, especially with regards to iterators for maps. | ||
* [[Encapsulate that which varies]] is used to make all variables accesses appear the same, even though they might be via an array, or directly accessed. The same is also true for the code itself, built-in operators have the same interface as user-defined functions. Making them easy to use interchangeably. | * [[Encapsulate that which varies]] is used to make all variables accesses appear the same, even though they might be via an array, or directly accessed. The same is also true for the code itself, built-in operators have the same interface as user-defined functions. Making them easy to use interchangeably. | ||
+ | * The implementation doesn't think [[Goto considered harmful]] it just happens that goto has not yet been required. However, if goto is introduced, it will be introduced as part of a failure path. | ||
+ | * The entire design employs [[Information hiding]] so that all of the code is can be represented by a single base class, and each different type of code generates its own output, without the code generator needing to know what it does. This also helps to implement [[Tell, Don't ask]]. | ||
+ | * [[Keep it simple]] is applied, each entity in the syntax tree of LTF is a seperate function in the parser. This makes it easy to follow the parsing path, and also to know what functions will/should be called next. The conflict with [[Big design up front]] is not an issue in this situation as the conflict is with a part of BDUF that is not being done. | ||
+ | * |
Revision as of 10:26, 29 September 2010
Contents |
Project (Programming Language Parser)
Description
My project is a parser for LTF (Logic, Types, Flow). The scope is limited to the parser only due to amount of work associated with writing a full compiler or interpreter, and the parser will sufficiently show/prove the design in implementation. I have a previous parser (written in C++) that can parse a language with similar logic/type declarations. However this project is mostly new, some parsing, OO, and language concepts are shared from the previous project.
Goals/Requirements
- Parse and create an AST (Abstract Syntax Tree) of the LTF.
About LTF
LTF is designed for writing code similar to the way the shell works, except with much more flexibility, as data can be pushed to any of the objects, not just in a forwards directions. Code is written in 3 seperate parts:
- Type information is the meta data describing each of the types in the system. (Like a header file)
- Logic is the code that implements the functionality of the types. (like normal code files)
- Flow creates objects and connects them together (similar to a main function)
Things to note:
- LTF supports single inherientance.
- LTF supports interfaces, on a per function basis.
- LTF is a push system, data always moves from in to out.
- input functions do not return a value, the correct solution is to input an error to the caller.
- Logic is pre-order, and bracketing is non-optional.
Design
Root types:
- Module (all of [name].{type,logic})
- Program (a program, described by a flow)
- AST (some item in the AST, an option of some sort)
- Connection (some item of flow)
Types inherieting from AST:
- CodeAST
- AccessorAST
Design Justification
- Code parsing has an inherent requirement for a Switch statement smell. I have placed all of the switch statements in the parsers. This prevents the need for switch statements in classes, or any later part of the processing.
- Overriding the code generation in each submodule, and having a single function definition that generates the code helps to Avoid downcasting.
- In the parsing the code Avoid side effects gives the global module a nextToken() and currToken() function, because most of the time the current token is required again, and storing it as a local variable would not work. Having nextToken() return anything does violate Keep accessors and mutators seperate however the benefit of not requiring the call to nextToken() then currToken() is worth this.
- Big design up front is used to for this project, because the language as a whole needs to be designed before a parser can be started. This is only the overall design however, the parser, AST storage, and code generation as designed as required throughout the project.
- Don't expose mutable attributes is applied, all classes provide getter and setter methods as required to access their internals. Further, Getters and setters rule for good design, version 2 is used. However in some places, especially with regards to iterators for maps.
- Encapsulate that which varies is used to make all variables accesses appear the same, even though they might be via an array, or directly accessed. The same is also true for the code itself, built-in operators have the same interface as user-defined functions. Making them easy to use interchangeably.
- The implementation doesn't think Goto considered harmful it just happens that goto has not yet been required. However, if goto is introduced, it will be introduced as part of a failure path.
- The entire design employs Information hiding so that all of the code is can be represented by a single base class, and each different type of code generates its own output, without the code generator needing to know what it does. This also helps to implement Tell, Don't ask.
- Keep it simple is applied, each entity in the syntax tree of LTF is a seperate function in the parser. This makes it easy to follow the parsing path, and also to know what functions will/should be called next. The conflict with Big design up front is not an issue in this situation as the conflict is with a part of BDUF that is not being done.