oryx 0.2.1 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +0 -1
- data/.travis.yml +15 -2
- data/README.md +13 -1
- data/doc/ast.md +110 -0
- data/doc/cflat.md +71 -0
- data/doc/conclusion.md +0 -0
- data/doc/fibonacci.md +15 -0
- data/doc/img/fib_parse.jpg +0 -0
- data/doc/intermediate_lang.md +0 -0
- data/doc/intro.md +89 -0
- data/doc/lexer.md +33 -0
- data/doc/parser.md +11 -0
- data/doc/symbol_table.md +23 -0
- data/doc/tools.md +9 -0
- data/doc/x86_translation.md +0 -0
- data/lib/oryx/ast.rb +34 -8
- data/lib/oryx/contractor.rb +185 -0
- data/lib/oryx/error.rb +8 -0
- data/lib/oryx/parser.rb +31 -7
- data/lib/oryx/runner.rb +30 -1
- data/lib/oryx/symbol_table.rb +48 -0
- data/lib/oryx/version.rb +1 -1
- data/lib/oryx.rb +3 -0
- data/test/data/add.c +3 -0
- data/test/data/div.c +3 -0
- data/test/data/eq.c +6 -0
- data/test/data/fib.c +8 -0
- data/test/data/fun_1.c +7 -0
- data/test/data/ge.c +6 -0
- data/test/data/geq.c +6 -0
- data/test/data/gvar_1.c +5 -0
- data/test/data/gvar_2.c +6 -0
- data/test/data/gvar_3.c +6 -0
- data/test/data/if.c +15 -0
- data/test/data/le.c +6 -0
- data/test/data/leq.c +6 -0
- data/test/data/mul.c +3 -0
- data/test/data/neq.c +6 -0
- data/test/data/return.c +3 -0
- data/test/data/sub.c +3 -0
- data/test/lib/oryx/error_test.rb +19 -0
- data/test/lib/oryx/runner_test.rb +25 -0
- data/test/lib/oryx/symbol_table_test.rb +147 -0
- data/test/shoulda_macros/runner.rb +58 -0
- data/test/test_helper.rb +1 -0
- metadata +61 -4
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -1,5 +1,18 @@
|
|
1
|
+
---
|
1
2
|
language: ruby
|
2
3
|
rvm:
|
3
|
-
|
4
|
-
|
4
|
+
- 1.9.3
|
5
|
+
- 2.0.0
|
6
|
+
before_script:
|
7
|
+
- "wget https://s3.amazonaws.com/oryx-artifacts/artifacts/40/40.1/llvm-cmpl-3.0.tar.gz"
|
8
|
+
- tar -xzf llvm-cmpl-3.0.tar.gz
|
9
|
+
- "export LD_LIBRARY_PATH=/home/travis/build/rampantmonkey/oryx/llvm-shared/lib:$LD_LIBRARY_PATH"
|
10
|
+
- "export PATH=/home/travis/build/rampantmonkey/oryx/llvm-shared/bin:$PATH"
|
11
|
+
|
5
12
|
script: bundle exec rake
|
13
|
+
env:
|
14
|
+
global:
|
15
|
+
- "ARTIFACTS_AWS_REGION=us-east-1"
|
16
|
+
- "ARTIFACTS_S3_BUCKET=oryx-artifacts"
|
17
|
+
- secure: "lIqFPSOg8pq/x/I55RRBD749/2ASnnBrf7trG+y1q2wu5SOEcYWHPGn+QvyzFL0q67c/Qnz1MYtn6GJOZXPnAWZrZOtlw9QgIkrk6NquiyUMfR6qQA79lMo79okyFxeyK7uedvVbCBxPgJK3CA2IcKIMmWkOU+LLvnTCl2veqh8="
|
18
|
+
- secure: "HN9A0olMrWO8TTmAEN7fg3qtJp08JqabIKVgujLWw+JHVRGqh9MBF9j5ra1WhdV3n7myi+A0v38Fe7T7Mi0gRd+OAp/eCLg2prO2/ZpobWduY5k22XwR0uujsPmv9W4EQalhauWx4kmAu/9rjPcO5Voe5mcvHoFK5xun1571vjM="
|
data/README.md
CHANGED
@@ -6,6 +6,16 @@ C-Flat to x86 compiler.
|
|
6
6
|
- 20 Feb 13
|
7
7
|
+ Oryx 0.1.1
|
8
8
|
+ Lexer complete
|
9
|
+
- 1 April 13
|
10
|
+
+ Oryx 0.2.1
|
11
|
+
+ Parse Tree successfully generated
|
12
|
+
- 3 April 13
|
13
|
+
+ Oryx 0.2.7
|
14
|
+
+ Symbol Table implemented
|
15
|
+
- 29 April 13
|
16
|
+
+ Oryx 0.3.1
|
17
|
+
+ Abstract Syntax Tree defined and generated
|
18
|
+
+ Fixed Travis errors by pre-compiling LLVM shared library
|
9
19
|
|
10
20
|
## C-Flat
|
11
21
|
C-Flat is a working subset of C designed for use in compilers courses. C-flat includes expressions, basic control flow, recursive functions, and strict type checking. It is object-compatible with ordinary C and thus can take advantage of the standard C library, at least when using limited types.
|
@@ -17,6 +27,7 @@ C-Flat is a working subset of C designed for use in compilers courses. C-flat in
|
|
17
27
|
## Requirements
|
18
28
|
|
19
29
|
- Ruby >= 1.9.3
|
30
|
+
- [LLVM 3.0](http://llvm.org/releases/) shared library
|
20
31
|
|
21
32
|
## Usage
|
22
33
|
|
@@ -27,7 +38,8 @@ For more details try
|
|
27
38
|
$ oryx -h
|
28
39
|
|
29
40
|
## See Also
|
30
|
-
|
41
|
+
|
42
|
+
`doc/intro.md`
|
31
43
|
|
32
44
|
|
33
45
|
## Contributing
|
data/doc/ast.md
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
# Abstract Syntax Tree
|
2
|
+
|
3
|
+
## Design
|
4
|
+
|
5
|
+
The abstract syntax tree serves as the data structure which bridges parsing and code generation. As such, there should be a simple mapping from parser to AST and from AST to intermediate code. The base class provided by RLTK is `ASTNode`. This class holds the functionality required for a tree: traversal and references to parents and children.
|
6
|
+
|
7
|
+
There are two methods for distinguishing between similar classes (e.g. `Oryx::Add` and `Oryx::Sub`): inheritance or additional parameter. Inheritance was chosen for this project because it is consistent with the traversal method in code generation and it is simpler to create additional objects with the parser.
|
8
|
+
|
9
|
+
## Construction
|
10
|
+
|
11
|
+
This section describes the creation of an AST from the token stream. Each grammar rule in the parser finds sequences of tokens which match the CFlat language. When the proper match is determined (see [parser documentation](parser.md) for details) Oryx generates a node in the tree. A simple example is the `Oryx::Number` class. This node has one attribute, the integer which the lexeme represents.
|
12
|
+
|
13
|
+
## Generation
|
14
|
+
|
15
|
+
This section introduces the code generation from the AST. During code generation, `Oryx` traverses the tree and emits intermediate code corresponding to the class type. For example consider `Oryx::Add`. This class has two values (inherited from `Oryx::Binary`) `left` and `right` which correspond directly to the LLVM instruction `add`.
|
16
|
+
|
17
|
+
## Class Hierarchy
|
18
|
+
|
19
|
+
|- Expression -|- Assign |- Add
|
20
|
+
|- ParamList |- Binary ---------|- Div
|
21
|
+
| | |- EQ
|
22
|
+
| | |- GE
|
23
|
+
| | |- GEQ
|
24
|
+
| | |- LE
|
25
|
+
| | |- LEQ
|
26
|
+
| | |- Mul
|
27
|
+
| | |- NEQ
|
28
|
+
| |
|
29
|
+
RLTK::ASTNode -|- ArgList |
|
30
|
+
| |- Call
|
31
|
+
|- Function |
|
32
|
+
|- CodeBlock
|
33
|
+
|- Declaration ------ GDeclaration
|
34
|
+
|- If
|
35
|
+
|- Initialization --- GInitialization
|
36
|
+
|- Number
|
37
|
+
|- Return
|
38
|
+
| |- Boolean
|
39
|
+
|- Type -----------|- Char
|
40
|
+
| |- Int
|
41
|
+
| |- Str
|
42
|
+
|- Variable
|
43
|
+
|- While
|
44
|
+
|
45
|
+
## Class Descriptions
|
46
|
+
|
47
|
+
Here the details of each class of the syntax tree defined in Oryx.
|
48
|
+
|
49
|
+
### Add
|
50
|
+
Subclass of `Binary` for addition.
|
51
|
+
### ArgList
|
52
|
+
List of expressions to be evaluated and passed to a function. Only used as a direct descendant of `Call`.
|
53
|
+
### Assign
|
54
|
+
Assign the result of an expression to a pre-existing variable.
|
55
|
+
### Binary
|
56
|
+
An abstraction designed to represent expressions which have two arguments - `left` and `right`.
|
57
|
+
### Boolean
|
58
|
+
Node representing the `boolean` data type.
|
59
|
+
### Call
|
60
|
+
Call a function with the given parameters.
|
61
|
+
### Char
|
62
|
+
Node representing the `character` data type.
|
63
|
+
### CodeBlock
|
64
|
+
A list of expressions surrounded by curly braces.
|
65
|
+
### Declaration
|
66
|
+
Declare a new variable with no value.
|
67
|
+
### Div
|
68
|
+
Subclass of `Binary` for division.
|
69
|
+
### EQ
|
70
|
+
Subclass of `Binary` for equality comparison.
|
71
|
+
### Expression
|
72
|
+
Generic base class, inherited from `RLTK::ASTNode` to simplify the interface between the external library.
|
73
|
+
### Function
|
74
|
+
Create a new function which contains a list of expressions and optional parameters.
|
75
|
+
### GDeclaration
|
76
|
+
Subclass of `Declaration` for variables declared in a global scope.
|
77
|
+
### GE
|
78
|
+
Subclass of `Binary` for greater-than comparison.
|
79
|
+
### GEQ
|
80
|
+
Subclass of `Binary` for greater-than-or-equal comparison.
|
81
|
+
### GInitialization
|
82
|
+
Subclass of `Initialization` for variables initialized in a global scope.
|
83
|
+
### If
|
84
|
+
Stores a conditional and two `CodeBlocks` (or `Expressions`) to be evaluated based on result of conditional.
|
85
|
+
### Initialization
|
86
|
+
Create a new variable with a default value.
|
87
|
+
### Int
|
88
|
+
Node representing the `integer` data type.
|
89
|
+
### LE
|
90
|
+
Subclass of `Binary` for less-than comparison.
|
91
|
+
### LEQ
|
92
|
+
Subclass of `Binary` for less-than-or-equal comparison.
|
93
|
+
### Mul
|
94
|
+
Subclass of `Binary` for multiplication.
|
95
|
+
### NEQ
|
96
|
+
Subclass of `Binary` for not-equal comparison.
|
97
|
+
### Number
|
98
|
+
Contains the numerical value of a lexeme; used for numerical constants.
|
99
|
+
### ParamList
|
100
|
+
List of formal parameters to a `Function`; used in a `Function` definition.
|
101
|
+
### Return
|
102
|
+
Return the value of the child of this node from a function.
|
103
|
+
### Str
|
104
|
+
Node representing the `string` data type.
|
105
|
+
### Type
|
106
|
+
Abstraction designed to represent data types.
|
107
|
+
### Variable
|
108
|
+
Variable lookup(or reference).
|
109
|
+
### While
|
110
|
+
While loop construct with a `CodeBlock` and an `Expression`.
|
data/doc/cflat.md
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# C-Flat 2013
|
2
|
+
|
3
|
+
C-Flat is a working subset of C designed for use in compilers courses. C-Flat includes expressions, control flow, recursion, and strict type checking. This document will outline an **informal** description of the language, its features, and design decisions.
|
4
|
+
|
5
|
+
## Keywords
|
6
|
+
|
7
|
+
- `boolean`
|
8
|
+
- `char`
|
9
|
+
- `else`
|
10
|
+
- `if`
|
11
|
+
- `int`
|
12
|
+
- `print`
|
13
|
+
- `return`
|
14
|
+
- `string`
|
15
|
+
- `true`
|
16
|
+
- `void`
|
17
|
+
- `while`
|
18
|
+
|
19
|
+
## Identifiers
|
20
|
+
|
21
|
+
Identifiers in C-Flat are identical to C. Identifiers may contain letters, numbers, and underscores and must begin with a letter or a number. Keywords are also not valid identifiers.
|
22
|
+
|
23
|
+
## Whitespace
|
24
|
+
|
25
|
+
C-Flat ignores whitespace (beyond separating identifiers).
|
26
|
+
|
27
|
+
## Operators
|
28
|
+
|
29
|
+
C-Flat includes many of the arithmetic operators found in C. Here they are enumerated with precedence.
|
30
|
+
|
31
|
+
( ) grouping ^ (highest precedence)
|
32
|
+
* / multiplication |
|
33
|
+
+ - addition |
|
34
|
+
< <= >= == != comparison |
|
35
|
+
&& logical and |
|
36
|
+
|| logical or |
|
37
|
+
= assignment --- (lowest precedence)
|
38
|
+
|
39
|
+
## Types
|
40
|
+
|
41
|
+
C-Flat is strictly typed. This means that there is no type casting or type promotion, which means that an error occurs when the operand types differ. C-Flat supports four or five types (depending on how you count). All types can be used as function return types and can all (except for void) be used as a type of variable.
|
42
|
+
|
43
|
+
### Integer
|
44
|
+
|
45
|
+
int x = 123;
|
46
|
+
|
47
|
+
`integers` are always signed 32-bit values.
|
48
|
+
|
49
|
+
### Character
|
50
|
+
|
51
|
+
char c = 'q';
|
52
|
+
|
53
|
+
`character` represents a single ASCII character.
|
54
|
+
|
55
|
+
### String
|
56
|
+
|
57
|
+
string s = "hello world\n";
|
58
|
+
|
59
|
+
A `string` is an immutable, doubly quoted list of `character`s.
|
60
|
+
|
61
|
+
### Boolean
|
62
|
+
boolean b = false;
|
63
|
+
|
64
|
+
`boolean` represents the literal values *true* and *false*.
|
65
|
+
|
66
|
+
### Void
|
67
|
+
|
68
|
+
Void is slightly different than all the other types. It can only be used in one context, the return type of a function. In this context, `void` indicates that the function does not return a value.
|
69
|
+
|
70
|
+
|
71
|
+
|
data/doc/conclusion.md
ADDED
File without changes
|
data/doc/fibonacci.md
ADDED
Binary file
|
File without changes
|
data/doc/intro.md
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# Project Description
|
2
|
+
|
3
|
+
[Oryx](https://github.com/rampantmonkey/oryx) is a compiler for the C-Flat language written in [Ruby](http://www.ruby-lang.org/en/).
|
4
|
+
|
5
|
+
# Goals
|
6
|
+
|
7
|
+
- Produce tokens from source code (Oryx 0.1.1)
|
8
|
+
- Create parse tree from token stream (Oryx 0.2.1)
|
9
|
+
- Symbol Table working (Oryx 0.2.7)
|
10
|
+
- Translate parse tree into AST (Oryx ?.?.?)
|
11
|
+
- Emit LLVM intermediate code by walking AST (Oryx ?.?.?)
|
12
|
+
- Implement Semantic Analysis (Oryx ?.?.?)
|
13
|
+
- Use LLVM optimizations (Oryx ?.?.?)
|
14
|
+
- Improved error handling (Oryx ?.?.?)
|
15
|
+
|
16
|
+
# Implementation Overview
|
17
|
+
|
18
|
+
Ruby was chosen as the implementation language since it supports numerous programming styles simultaneously. This feature allows Oryx to use the [programming paradigm](http://en.wikipedia.org/wiki/Programming_paradigm) which most directly models each piece of the compiler. The alternative being choosing one paradigm and forcing each piece of the compiler to fit that model. Ruby elegantly [combines three programming paradigms](http://en.wikipedia.org/wiki/Ruby_(programming_language)) which can produce powerful code that is easy to understand. The three paradigms -- [imperative](http://en.wikipedia.org/wiki/Imperative_programming), [functional](http://en.wikipedia.org/wiki/Functional_programming), and [object oriented](http://en.wikipedia.org/wiki/Object-oriented_programming) -- each shine with different types of problems.
|
19
|
+
|
20
|
+
Imperative techniques are a direct abstraction of the capabilities of the execution environment and are therefore provide the least friction when interfacing with the machine (I/O in this program). The functional paradigm is the programming language incarnation of mathematical theory. Due to the strong link to theory, it is simple to implement compiler design (also based strongly in theory). The object oriented paradigm comes from observations about biological systems. Under this paradigm programs are constructed as independent units which communicate, and therefore get work done, by sending messages to other objects. Object oriented techniques tend to be useful for code organization due to their compartmentalization.
|
21
|
+
|
22
|
+
Beyond the theoretical reasoning, Ruby has many practical advantages. Ruby's main focus is developer happiness (reference). This goal has lead to many development tools, libraries, and distribution mechanisms. Unit testing (with automation) and static [code analysis](http://codeclimate.org) are two of the development tools I used to assist development of Oryx. Ruby uses gems as the main mechanism for sharing and distributing libraries. The main library used is [RLTK](https://github.com/chriswailes/RLTK). The Ruby Language Tool Kit provides a lexer generator, parser generator, abstract syntax tree nodes, and LLVM bindings.
|
23
|
+
|
24
|
+
My familiarity with Ruby re-enforced the choice of language.
|
25
|
+
|
26
|
+
# Program Flow
|
27
|
+
|
28
|
+
#####################
|
29
|
+
# #
|
30
|
+
# source #
|
31
|
+
# #
|
32
|
+
#####################
|
33
|
+
|
|
34
|
+
| Character by character
|
35
|
+
|
|
36
|
+
V
|
37
|
+
#####################
|
38
|
+
# #
|
39
|
+
# lexer #
|
40
|
+
# #
|
41
|
+
#####################
|
42
|
+
|
|
43
|
+
| Token Stream
|
44
|
+
|
|
45
|
+
V
|
46
|
+
#####################
|
47
|
+
# #
|
48
|
+
# parser #
|
49
|
+
# #
|
50
|
+
#####################
|
51
|
+
|
|
52
|
+
| Abstract Syntax Tree
|
53
|
+
|
|
54
|
+
V
|
55
|
+
#####################
|
56
|
+
# #
|
57
|
+
# semantic #
|
58
|
+
# analysis #
|
59
|
+
# #
|
60
|
+
#####################
|
61
|
+
|
|
62
|
+
| Verified Syntax Tree
|
63
|
+
|
|
64
|
+
V
|
65
|
+
#####################
|
66
|
+
# #
|
67
|
+
# code #
|
68
|
+
# generation #
|
69
|
+
# #
|
70
|
+
#####################
|
71
|
+
|
|
72
|
+
| Executable (via LLVM)
|
73
|
+
|
|
74
|
+
V
|
75
|
+
|
76
|
+
|
77
|
+
# Table of Contents
|
78
|
+
|
79
|
+
- [Introduction](intro.md)
|
80
|
+
- [C-Flat](cflat.md)
|
81
|
+
- [Tools Available](tools.md)
|
82
|
+
- [Lexer](lexer.md)
|
83
|
+
- [Parser](parser.md)
|
84
|
+
- [Abstract Syntax Tree](ast.md)
|
85
|
+
- [Symbol Table](symbol_table.md)
|
86
|
+
- [Intermediate Representation](intermediate_lang.md)
|
87
|
+
- [Translation into x86 Assembly](x86_translation.md)
|
88
|
+
- [Conclusion](conclusion.md)
|
89
|
+
|
data/doc/lexer.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# Lexer
|
2
|
+
|
3
|
+
The lexer is the first step in the compilation of C-Flat. The input for the lexer is the raw source code and the output is a stream of tokens. The lexer processes the source file one character at a time looking for valid *tokens*. Some examples of valid tokens are identifiers, punctuation (commas, semi colons, parentheses, etc.), and string constants. The lexer also removes comments and whitespace.
|
4
|
+
|
5
|
+
The main mechanism behind the lexer is a finite automaton. The states are defined by a series of regular expressions. The regular expressions are joined together to form an automaton which represents all of the valid tokens in C-Flat (as well as some error tokens).
|
6
|
+
|
7
|
+
|
8
|
+
## Lexer Rules
|
9
|
+
|
10
|
+
Each regular expression is designed to find one type of lexeme and return the corresponding token when complete. Ruby's [block semantics](http://c2.com/cgi/wiki?BlocksInRuby) provide a convienent method for expressing this idiom. Blocks are essentially anonymous functions which can be stored and executed later. Here is an example from the lexer source code.
|
11
|
+
|
12
|
+
rule(/^[^\d\W]\w*/) { |t| [:IDENT, t] }
|
13
|
+
|
14
|
+
There are two important things to know in order to truly appreciate this line of code. The code is divided into two pieces, the rule definition and the function to execute on a successful match. The rule method adds the regular expression to the state machine as a valid pattern. The block has one parameter `t` which represents the matched lexeme and returns a token of type `IDENT` and containing the matched lexeme.
|
15
|
+
|
16
|
+
|
17
|
+
## Lexer States
|
18
|
+
|
19
|
+
Some rules do not require a lexeme, e.g. `IF` or `WHILE`. And some are more complicated requiring an additional lexer feature. This additional feature is states and is required for processing string constants and comments.
|
20
|
+
|
21
|
+
The term *states* is overloaded in this context so I will use the term *lexer state* when referring to the lexer feature, otherwise I am referring to the 'states' of the finite automaton.
|
22
|
+
|
23
|
+
Without *lexer states* each of the accepting states return to the initial start state. *lexer states* can be viewed as an additional start state to which additional rules may be attached or as a new [namespace](http://en.wikipedia.org/wiki/Namespace_(computer_science)) in which to define new rules. The separation created by *lexer states* is useful in processing strings and comments since the only important character is the comment/string terminator. When this token is encountered the *lexer state* is exited and lexing returns to the default state.
|
24
|
+
|
25
|
+
|
26
|
+
## Lexer Flags
|
27
|
+
|
28
|
+
One final feature which improves the robustness of the lexer is *flags*. Flags represent certain conditions which should result in an error upon exit but are not currently an error. One such case is comments. A source code file with an unclosed comment is most likely a mistake and is defined as an error in the language specification. Thus Oryx needs to detect this issue.
|
29
|
+
|
30
|
+
Flags are boolean values. Oryx uses one flag for comment processing, which is `true` during comment processing and `false` otherwise. When the `EOF` character is read, the lexer checks the status of each flag and prints an error message if the flag is set.
|
31
|
+
|
32
|
+
|
33
|
+
|
data/doc/parser.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# Parser
|
2
|
+
|
3
|
+
The parser defines the grammar (sentence structure) of CFlat. The grammar is built by combining many small rules together. The rules are defined in a similar fashion to the [lexer](lexer.md). Each rule consists of a pattern and a function to construct the correct syntax node.
|
4
|
+
|
5
|
+
The structure of parse rules has two minor differences from the lexer. Since the input to the parser is a stream of `Token`s a basic string can be used to define the pattern instead of a regular expression which corresponds to the decrease in complexity of the input. The functions to return/construct syntax tree nodes are more complicated than the lexer. The lexer only returned one class, `RLTK::Token`, while the parser selects a more descriptive class (see [ast](ast.md)).
|
6
|
+
|
7
|
+
A few developer niceties are provided by RLTK. Rules can be grouped and named to reduce redundancy. Rules also have an optional precedence hierarchy and directional associativity (left or right). There is also an option to output the parse tree in [`dot`](http://graphviz.org/) syntax to create a visual representaton of parsing. A final feature is the ability to produce a state diagram of the parser.
|
8
|
+
|
9
|
+
## Parsing Algorithm
|
10
|
+
|
11
|
+
RLTK uses the [GLR](http://en.wikipedia.org/wiki/GLR_parser)(generalized "LR") parsing algorithm. GLR, originally published in 1984, is an extension of the LR algorithm designed to handle ambiguities and conflicts between rules. Typical LR parsers only allow one transition per state per token. This creates the potential for shift/reduce and reduce/reduce conflicts. GLR allows multiple transitions, effectively eliminating these types of conflicts. This feature is implemented by forking the parse stack and continuing parsing along both paths. To handle the potential for an explosion in memory usage common prefixes and suffixes are shared among each stack.
|
data/doc/symbol_table.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Symbol Table
|
2
|
+
|
3
|
+
The symbol table is a key data structure used during the semantic analysis and code generation phases of compilation. Thus a correct and efficient implementation is vital to the success of this project. Here we will discuss the implementation of symbol tables used in Oryx from the basic operations necessary to the design decisions made during development.
|
4
|
+
|
5
|
+
## Basic Operations
|
6
|
+
|
7
|
+
A symbol table for C-Flat has to support 5 basic operations -- `insert`, `update`, `lookup`, `enter` scope, and `exit` scope. When a variable is declared, regardless of the context, `insert` is used to store the fact that a variable exists. Assigning a value to a variable, whether during initialization or as the result of an expression, requires `update`. It is only possible to `update` a variable that has already been inserted into the table. `lookup` returns the value associated with a given variable. `enter` and `exit` scope are called when entering/exiting a code block which allows previously defined variables to be redefined temporarily.
|
8
|
+
|
9
|
+
## Data Structures
|
10
|
+
|
11
|
+
The 5 basic operations can be divided into two groups. `insert`, `update`, and `lookup` form the first group while `enter`, `exit` form the second. When looking at these two groupings it is apparent that there is a different data structure which supports each set of instructions. The first group directly maps to a hash table and the second to a stack. These conceptual data structures are represented differently in various programming languages. First we will look at how Ruby provides these structures, then we will see how to combine them into a symbol table.
|
12
|
+
|
13
|
+
### Hash Tables in Ruby
|
14
|
+
|
15
|
+
As part of the language, Ruby provides a [`Hash` class](http://ruby-doc.org/core-2.0/Hash.html) which implements a hash table. `Hash` stores and retrieves objects by label. A label can be any object which implements the `==` (equality) operator, but the typical objects used for labels are [`String`](http://ruby-doc.org/core-2.0/String.html) and [`Symbol`](http://ruby-doc.org/core-2.0/Symbol.html). `String`s are, as expected, a list of characters. `Symbol`s can be viewed as strings with two important distinctions. `Symbol`s are __immutable__ and __globally__ scoped. `Symbol`s are implemented as a pointer to a memory object containing the name of the symbol, thus comparisons are extremely fast. All of these properties make `Symbol`s an ideal choice for storing values in a hash table.
|
16
|
+
|
17
|
+
### Stacks in Ruby
|
18
|
+
|
19
|
+
Ruby does not provide a specific `stack` class, however the `push` and `pop` methods are implemented for the [`Array` class](http://ruby-doc.org/core-2.0/Array.html).
|
20
|
+
|
21
|
+
## Bringing It Together
|
22
|
+
|
23
|
+
Combining these data structures into a symbol table is straight forward. The symbol table is implemented as an `Array` of `Hash`es. The first `Hash` in the `Array` represents the global program scope while successive elements represent more localized scopes. When a function exits the last entry is removed from the `Array`, effectively destroying the values created inside of the scope.
|
data/doc/tools.md
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# Tools Available
|
2
|
+
|
3
|
+
## RLTK
|
4
|
+
|
5
|
+
[The Ruby Language Toolkit](https://github.com/chriswailes/RLTK) (or RLTK) by [Chris Wailes](http://chris.wailes.name/) provides a large collection of tools useful for translating languages - lexer generator, parser generator, abstract syntax tree node base class, and LLVM bindings. RLTK is also well documented and includes tutorials on constructing compilers. The LLVM bindings are of particular interest since it is rapidly evolving into an important part of the development toolchain.
|
6
|
+
|
7
|
+
## Others
|
8
|
+
|
9
|
+
Ruby provides a [foreign function interface](https://github.com/ffi/ffi) for interfacing with C functions and libraries. This means that any options from C, such as `yacc`, are available in Ruby. There are also options to interface with Java libraries so jcup and jflex would also be possibilities. The downside to all of these options is that they require a translation layer between Ruby and the library, which reduces the usefulness of Ruby.
|
File without changes
|
data/lib/oryx/ast.rb
CHANGED
@@ -7,8 +7,13 @@ module Oryx
|
|
7
7
|
value :value, Integer
|
8
8
|
end
|
9
9
|
|
10
|
+
class Type < Expression
|
11
|
+
value :t, String
|
12
|
+
end
|
13
|
+
|
10
14
|
class Variable < Expression
|
11
15
|
value :name, String
|
16
|
+
child :type, Type
|
12
17
|
end
|
13
18
|
|
14
19
|
class Binary < Expression
|
@@ -16,11 +21,39 @@ module Oryx
|
|
16
21
|
child :right, Expression
|
17
22
|
end
|
18
23
|
|
24
|
+
class Initialization < Expression
|
25
|
+
value :name, String
|
26
|
+
child :right, Expression
|
27
|
+
child :type, Type
|
28
|
+
end
|
29
|
+
|
30
|
+
class GInitialization < Initialization; end
|
31
|
+
|
32
|
+
class Declaration < Expression
|
33
|
+
value :name, String
|
34
|
+
child :type, Type
|
35
|
+
end
|
36
|
+
|
37
|
+
class GDeclaration < Declaration; end
|
38
|
+
|
19
39
|
class Assign < Expression
|
20
40
|
value :name, String
|
21
41
|
child :right, Expression
|
22
42
|
end
|
23
43
|
|
44
|
+
class ParamList < RLTK::ASTNode
|
45
|
+
child :params, [Declaration]
|
46
|
+
end
|
47
|
+
|
48
|
+
class ArgList < RLTK::ASTNode
|
49
|
+
child :args, [Expression]
|
50
|
+
end
|
51
|
+
|
52
|
+
class Call < Expression
|
53
|
+
value :name, String
|
54
|
+
child :args, ArgList
|
55
|
+
end
|
56
|
+
|
24
57
|
class Add < Binary; end
|
25
58
|
class Sub < Binary; end
|
26
59
|
class Mul < Binary; end
|
@@ -47,14 +80,11 @@ module Oryx
|
|
47
80
|
child :statements, [Expression]
|
48
81
|
end
|
49
82
|
|
50
|
-
class ParamList < RLTK::ASTNode
|
51
|
-
child :params, [Expression]
|
52
|
-
end
|
53
|
-
|
54
83
|
class Function < RLTK::ASTNode
|
55
84
|
value :i, String
|
56
85
|
child :params, ParamList
|
57
86
|
child :body, CodeBlock
|
87
|
+
child :return_type, Type
|
58
88
|
end
|
59
89
|
|
60
90
|
class While < Expression
|
@@ -62,10 +92,6 @@ module Oryx
|
|
62
92
|
child :body, CodeBlock
|
63
93
|
end
|
64
94
|
|
65
|
-
class Type < Expression
|
66
|
-
value :t, String
|
67
|
-
end
|
68
|
-
|
69
95
|
class Boolean < Type; end
|
70
96
|
class Char < Type; end
|
71
97
|
class Int < Type; end
|