Gaddis pseudocode compiler implementation, based on "Starting Out with Programming Logic and Design" by Tony Gaddis
- Abstract Syntax Tree (AST)
- Handwritten lexer to tokenize Gaddis pseudocode
- Handwritter parser to build the AST
- Symbol resolution, type checking, control flow validation
- Psuedo assembly language and interpreter
- Go code generator to transliterate the AST into Go code, allowing native execution.
- Syntax highlighting
- Autoformat
- Inline compile errors
- Debug Adapter Protocol (DAP) debugger
- Download
gaddis-vscode.vsixfrom the latest release. - VSCode -> Settings -> Extensions->
... Install from VSIX...
(See gaddis help for additional commands.)
go install github.com/dragonsinth/gaddis/...Runs the given file interactively.
gaddis run ./examples/chapter2/2.gadWhat were the annual sales?
integer> 120000
The company made about $27600
Runs the given file as a test, using 2.gad.in as program input,
and 2.gad.out as the expected test output.
gaddis test ./examples/chapter2/2.gadPASSED
NOTE: the first time test is run on a file, if input and output files
do not yet exist, gaddis test will run in "capture" mode, potentially
reading from stdin to create input and output files for subsequent test runs.
All legal language constructs should be supported now.
- Basic statements, expressions, operations, variables, constants, control structures.
Integer,Real,String,Character,BooleanInput,DisplayModuleandFunctiondeclarations- Arrays,
For Each - Indexing
StringasCharacter - External function library
- File I/O
- Classes
Some semantic checks are still missing (see below), allowing some illegal code to run.
-
Classes
- Enforce
Public/Privatein type checking - Prevent certain types of class super/sub name collisions?
- implicit/required super constructor calls...?
- Enforce
-
Consider extending multi-line parsing/printing to all comma-delimited lists:
- parameter lists
- argument lists
- Display/Read/Write
-
Consider enforcing field vs. record separators in file I/O.
Gaddis Pseudocode is a bit underspecified (on purpose), so I've had to make a few choices here and there, or fill in gaps. Here's some possible differences (clarifications?) from the book:
-
Characteris an explicit typeCharacterliterals are denoted using single-quoted characters:'X'Charactercan be implicitly cast to a String of length 1.- (
Charactertype is listed in the reference but not the main text.)
-
Stringvalues are immutable and copy-on-write under the hood. Updating a string in any way creates a newStringand assigns it back into the given reference; no other copies of the originalStringare affected. -
All expressions are evaluated left to right, including assignment statements.
-
Displaystatements only accept primitive types, not arrays or classes. -
Local variables (other than arrays) are never automatically initialized.
- Unconditional read before assignment will generate a compile error.
- Conditional read before assignment will generate a runtime error.
-
Forloop variable expression is evaluated once on loop start, and again once per iteration. -
Forloop stop expression is re-evaluated on every iteration. -
Forloop step expression must be a numeric constant.- This is implied by the book but not explicitly stated.
- Avoids more complicated code generation where the test expression (
<=vs>=) would need to change each iteration depending on the current value of the step expression. - Contrast with Basic's
downtokeyword.
-
For Eachloop reference expression is evaluated once per iteration. -
For Eachloop array expression is evaluated only once when the loop is initialized. -
New library function:
toString()convert a value of any type to String.- (In the book, this conversion only happens when invoking a
Displaystatement, but it seems like an obvious addition for useful string processing and formatting.)
- (In the book, this conversion only happens when invoking a
-
Nested
ModuleandFunctiondeclarations are not supported.- (This is implied by the book but not explicitly stated.)
-
Programs with a
Module main()are allowed to first execute arbitrary statements in the global block.- Global block statements first execute in lexical order, then
main()is called afterward.
- Global block statements first execute in lexical order, then
-
Inputstatements internally loop until the user inputs a line that can be correctly parsed to the type of the input variable; e.g. a non-numeric input will loop and retry if the input variable is anInteger.- The variable expression is only evaluated once, regardless.
-
By contrast,
Readstatements in anInputFilewhere the record data is the wrong type exit the program immediately with an exception. -
Arrays are filled with zero values on initialization when there is no initializer. When too few initializer expressions are provided, the remainder of the array is filled with zero values.
- (Should too few initializer expressions be an error? It's not clear.)
-
Array initializers are currently the only construct that may be parsed across multiple lines.
- There are explicit examples of this in the book.
- All other statements always appear on a single line.
- (Should we allow line breaks across other comma-delimited lists like parameter or argument lists?)
-
Arrays are deep copied when passed by value.
- (Implied by the book, but not explicitly stated.)
-
Array variables cannot be reassigned.
- (Implied by the book, but not explicitly stated.)
-
Array elements which are themselves Arrays (ie, part of a multidimensional array) cannot be reassigned either.
- For example, given
Integer table[3][4], row[4], you cannotSet table[0] = someRow. - However, such elements may be passed as arguments, either by value or reference.
- For example,
Call printValues(table[3])is legal. - (Implied by the book, but not explicitly stated.)
- For example, given
-
Arrays cannot be the return value of a Function
- (Implied by the book, but not explicitly stated.)
-
Use
Callto call the external library string modulesinsertanddelete.- This seems like an oversight / misprint? Otherwise, these two modules would have a unique syntax just to themselves.
-
Printoutputs to stderr; we didn't implement print support 😁 -
The
Fileabstraction is implemented as a newline separated text file.- Individual values are written (and read) exactly like in-code literals, for example:
Trueis aBooleanvalue1.3is aRealvalue"hello"is aStringvalue
- Each line in a file represents a single record (a single
ReadorWritestatment). - In multi-value records, fields are separated with a single tab character
\t. - All
Readoperations must specify the correct number and type(s) of fields matching the file data.- Reading the incorrect number or type of fields is an error.
- The last record in the file must end with a newline character.
- Individual values are written (and read) exactly like in-code literals, for example:
-
All
Classfields are zero-initialized before any user constructor starts running. -
Unresolved: what are the rules around calling super constructor methods from a subclass constructor?
- Should it work like Java?