├── .idea
├── .gitignore
├── modules.xml
├── pogo.iml
└── vcs.xml
├── README.md
├── fibo.pogo
├── go.mod
├── go.sum
├── main.go
├── pogologo.png
├── src
├── lang.bnf
├── lexer
│ ├── acttab.go
│ ├── lexer.go
│ └── transitiontable.go
├── parser
│ ├── parser.go
│ └── util.go
├── semantic
│ ├── CodeGenerator.go
│ ├── SemanticCube.go
│ ├── SymbolTable.go
│ └── util.go
├── shared
│ └── Types.go
├── storer
│ └── Serializer.go
├── token
│ ├── context.go
│ └── token.go
├── util
│ ├── litconv.go
│ └── rune.go
└── virtualmachine
│ ├── Memory.go
│ └── VirtualMachine.go
└── tests
├── pogo_parser_tests
├── conditionals.pogo
├── pogoPatito.pogo
├── pogoparser_test.go
└── simple.pogo
└── scanner_test.go
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/pogo.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Pogo Compiler
2 |
3 |
4 |
5 |
6 | A compiler for the **Pogo** programming language, implemented in Go. This hybrid compiler performs **lexical analysis**, **syntax parsing**, **semantic validation**, **intermediate code generation** and **code execution**.
7 |
8 | ## Features
9 |
10 | - **Lexical Analysis**: Token recognition powered by GOCC
11 | - **Recursive Descent Parsing**: Efficient parsing for context-free grammar
12 | - **Symbol Table Management**: Tracks identifiers and scope for variables and functions
13 | - **Type Checking**: Uses a semantic cube for enforcing type rules
14 | - **Data Type Support**: Handles basic data types like `int` and `float`
15 | - **Function Declarations & Calls**: Supports defining and invoking functions
16 | - **Control Structures**: Implements control flow with `if` and `while` statements
17 |
18 | ## Examples
19 |
20 | ### Important Notes
21 | - **Variable Declaration**: Variables can only be declared at the start of the program after program name and before function declarations, variables can also be declared within functions before any statement.
22 | - **Functions**: Currently functions are only void functions.
23 | - **Variable Types**: The program currently only handles ints and floats, booleans and comparisons are handled as ints.
24 |
25 | ### Example 1 Factorial
26 | ```
27 | program Factorial;
28 |
29 | var result : float;
30 | var x : int;
31 |
32 | begin
33 | // Comments work as well!!!!
34 | /*
35 | multiline comments also work!
36 | look!
37 | */
38 | result = 1;
39 | x = 5;
40 | while (x > 0) {
41 | result = result * x;
42 | x = x - 1;
43 | }
44 | print("This is the result", result)
45 | end
46 | ```
47 |
48 | ### Example 2 Fibonacci
49 |
50 | ```
51 | program recursiveFibo;
52 |
53 | var result : int;
54 |
55 | func fib(n : int) {
56 | var temp1, temp2 : int;
57 |
58 | if(n < 2) {
59 | result = n;
60 | } else {
61 | temp1 = n - 1;
62 | temp2 = n - 2;
63 | fib(temp1)
64 | temp1 = result;
65 | fib(temp2)
66 | temp2 = result;
67 | result = temp1 + temp2;
68 | }
69 | };
70 |
71 | begin
72 | fib(30)
73 | print("This is the result", result)
74 | end
75 | ```
76 |
77 | ## How to Run
78 | How to Run
79 |
80 | The main.go script demonstrates the compilation and execution process:
81 |
82 | ### Lexical Analysis:
83 |
84 | Create a lexer object by passing an input file
85 | Generate tokens through lexical analysis
86 |
87 |
88 | ### Parsing:
89 |
90 | Initialize the parser with the lexer tokens
91 | Perform recursive descent parsing
92 |
93 |
94 | ### Compilation:
95 |
96 | Generate a binary file containing compiled data
97 | Serialize necessary information for VM execution
98 |
99 |
100 | ### Execution:
101 |
102 | Load the compiled binary file
103 | Execute the virtual machine
104 |
105 |
106 | ### Example Workflow
107 |
108 | ```
109 | lex := lexer.NewLexer(inputFile)
110 |
111 | // Initialize parser
112 | parser := parser.NewParser(lex)
113 |
114 | // Parse the program
115 | parser.ParseProgram()
116 |
117 | // Save compiled data
118 | storer.SaveCompiledData(parser.CodeGenerator.Quads, parser.SymbolTable, parser.CodeGenerator.MemoryManager, "output.pbin")
119 |
120 | // Load and execute
121 | vm := storer.LoadCompiledData("output.pbin")
122 | vm.Execute()
123 | ```
124 |
--------------------------------------------------------------------------------
/fibo.pogo:
--------------------------------------------------------------------------------
1 | program recursiveFibo;
2 |
3 | var result : int;
4 |
5 | func fib(n : int) {
6 | var temp1, temp2 : int;
7 |
8 | if(n < 2) {
9 | result = n;
10 | } else {
11 | temp1 = n - 1;
12 | temp2 = n - 2;
13 | fib(temp1)
14 | temp1 = result;
15 | fib(temp2)
16 | temp2 = result;
17 | result = temp1 + temp2;
18 | }
19 | };
20 |
21 | begin
22 | fib(30)
23 | print("This is the result", result)
24 | end
25 |
26 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module pogo
2 |
3 | go 1.23.2
4 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pabloerhard/pogo/61af920b679f24243272bf246a3cb25561dc839a/go.sum
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "pogo/src/lexer"
7 | "pogo/src/parser"
8 | "pogo/src/storer"
9 | )
10 |
11 | func main() {
12 | inputFile := os.Args[len(os.Args)-1]
13 | input, err := os.ReadFile(inputFile)
14 |
15 | if err != nil {
16 | fmt.Printf("error reading input: %v", err)
17 | return
18 | }
19 |
20 | lex := lexer.NewLexer(input)
21 | p := parser.NewParser(lex)
22 |
23 | err = p.ParseProgram()
24 | if err != nil {
25 | fmt.Println("Parse error:", err)
26 | return
27 | }
28 |
29 | if err := storer.SaveCompiledData(p.CodeGenerator.Quads, p.SymbolTable, p.CodeGenerator.MemoryManager, "test.pbin"); err != nil {
30 | fmt.Println(err)
31 | return
32 | }
33 |
34 | vm, err := storer.LoadCompiledData("test.pbin")
35 | if err := vm.Execute(); err != nil {
36 | fmt.Println(err)
37 | return
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/pogologo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pabloerhard/pogo/61af920b679f24243272bf246a3cb25561dc839a/pogologo.png
--------------------------------------------------------------------------------
/src/lang.bnf:
--------------------------------------------------------------------------------
1 | // === [ Lexical part] =========================================================
2 | terminator : ';' ;
3 | repeatTerminator : ',';
4 | // --- [ Types ] ---------------------------------------------------------------
5 | type : 'i' 'n' 't' | 'f' 'l' 'o' 'a' 't' ;
6 |
7 | // --- [ Pre-defined KeyWords ] ---------------------------------------------------------------
8 | kwdIf : 'i' 'f';
9 | kwdElse : 'e' 'l' 's' 'e';
10 | kwdWhile : 'w' 'h' 'i' 'l' 'e';
11 | kwdPrint : 'p' 'r' 'i' 'n' 't';
12 | kwdFunc : 'f' 'u' 'n' 'c';
13 | kwdProgram : 'p' 'r' 'o' 'g' 'r' 'a' 'm' ;
14 | kwdBegin : 'b' 'e' 'g' 'i' 'n' ;
15 | kwdEnd : 'e' 'n' 'd' ;
16 | kwdVars : 'v' 'a' 'r' ;
17 |
18 | // --- [ Operators ] -----------------------------------------------------------
19 | relOp : '=' '=' | '!' '=' | '<' | '>' ;
20 | expressionOp : '+' | '-' ;
21 | termOp : '*' | '/' ;
22 | assignOp : '=' ;
23 | typeAssignOp : ':' ;
24 | openBrace : '{';
25 | closeBrace : '}';
26 | openParan : '(';
27 | closeParan : ')';
28 |
29 | // --- [ Identifiers ] ---------------------------------------------------------
30 | _asciiLetter : 'a' - 'z' | 'A' - 'Z' ;
31 | _letter : _asciiLetter | '_' ;
32 | _decimalDigit : '0' - '9' ;
33 | id : _letter { _letter | _decimalDigit } ;
34 |
35 | // --- [ Literals ] ---------------------------------------------------------
36 | intLit : '0' | '1' - '9' { _decimalDigit} ;
37 | floatLit : _decimalDigit '.' _decimals ;
38 | _decimals : _decimalDigit {_decimalDigit} ;
39 | stringLit : _rawStrLit | _interpretedStrLit ;
40 | _rawStrLit : '`' { . } '`' ;
41 | _escapeChar : '\\' 'n' | '\\' 'r' | '\\' 't' ;
42 | _interpretedStrLit : '"' { . | '\\' '"' | _escapeChar } '"' ;
43 |
44 | // --- [ Suppressed ] ---------------------------------------------------------
45 | !comment : _lineComment | _blockComment ;
46 | !whitespace : ' ' | '\t' | '\n' | '\r' ;
47 | _lineComment : '/' '/' {.} '\n' ;
48 | _blockComment : '/' '*' {. | '*'} '*' '/' ;
49 |
50 | // === [ Syntax part] =========================================================
51 | //Program
52 | // : ProgramName VarDeclarationSection FunctionListOpt MainSection <<>>
53 | // ;
54 | //
55 | //ProgramName
56 | // : kwdProgram id terminator
57 | // ;
58 | //
59 | //VarDeclarationSection
60 | // : empty
61 | // | VarDeclaration VarDeclarationSection
62 | // ;
63 | //
64 | //VarDeclaration
65 | // : kwdVars VarList typeAssignOp type terminator
66 | // ;
67 | //
68 | //VarList
69 | // : id
70 | // | VarList repeatTerminator id
71 | // ;
72 | //
73 | //FunctionListOpt
74 | // : FunctionList
75 | // | empty
76 | // ;
77 | //
78 | //FunctionList
79 | // : Function
80 | // | FunctionList Function
81 | // ;
82 | //
83 | //Function
84 | // : kwdFunc id openParan ParameterList closeParan Block terminator
85 | // ;
86 | //
87 | //Block
88 | // : openBrace StatementList closeBrace
89 | // ;
90 | //
91 | //ParameterList
92 | // : Parameter
93 | // | ParameterList repeatTerminator Parameter
94 | // | empty
95 | // ;
96 | //
97 | //Parameter
98 | // : id typeAssignOp type
99 | // ;
100 | //
101 | //MainSection
102 | // : kwdBegin StatementList kwdEnd
103 | // ;
104 | //
105 | //StatementList
106 | // : Statement
107 | // | StatementList Statement
108 | // ;
109 | //
110 | //Statement
111 | // : IfStatement
112 | // | PrintStatement terminator
113 | // | Assignment terminator
114 | // | FunctionCall terminator
115 | // | WhileStatement
116 | // ;
117 | //
118 | //IfStatement
119 | // : SimpleIfStatement
120 | // | IfElseStatement
121 | // ;
122 | //
123 | //SimpleIfStatement
124 | // : kwdIf openParan Expression closeParan Block
125 | // ;
126 | //
127 | //IfElseStatement
128 | // : kwdIf openParan Expression closeParan Block kwdElse Block
129 | // ;
130 | //
131 | //WhileStatement
132 | // : kwdWhile openParan Expression closeParan Block
133 | // ;
134 | //
135 | //PrintStatement
136 | // : kwdPrint openParan PrintList closeParan
137 | // ;
138 | //
139 | //PrintList
140 | // : PrintItem
141 | // | PrintList repeatTerminator PrintItem
142 | // ;
143 | //
144 | //PrintItem
145 | // : Expression
146 | // | stringLit
147 | // ;
148 | //
149 | //Assignment
150 | // : id assignOp Expression
151 | // ;
152 | //
153 | //FunctionCall
154 | // : id openParan ArgumentList closeParan
155 | // ;
156 | //
157 | //ArgumentList
158 | // : Expression
159 | // | ArgumentList repeatTerminator Expression
160 | // | empty
161 | // ;
162 | //
163 | //Expression
164 | // : Exp
165 | // | Exp relOp Exp
166 | // ;
167 | //
168 | //Exp
169 | // : Term
170 | // | Term expressionOp Exp
171 | // ;
172 | //
173 | //Term
174 | // : Factor
175 | // | Term termOp Factor
176 | // ;
177 | //
178 | //Factor
179 | // : openParan Expression closeParan
180 | // | expressionOp id
181 | // | expressionOp intLit
182 | // | expressionOp floatLit
183 | // | id
184 | // | intLit
185 | // | floatLit
186 | // ;
--------------------------------------------------------------------------------
/src/lexer/acttab.go:
--------------------------------------------------------------------------------
1 | // Code generated by gocc; DO NOT EDIT.
2 |
3 | package lexer
4 |
5 | import (
6 | "fmt"
7 |
8 | "pogo/src/token"
9 | )
10 |
11 | type ActionTable [NumStates]ActionRow
12 |
13 | type ActionRow struct {
14 | Accept token.Type
15 | Ignore string
16 | }
17 |
18 | func (a ActionRow) String() string {
19 | return fmt.Sprintf("Accept=%d, Ignore=%s", a.Accept, a.Ignore)
20 | }
21 |
22 | var ActTab = ActionTable{
23 | ActionRow{ // S0
24 | Accept: 0,
25 | Ignore: "",
26 | },
27 | ActionRow{ // S1
28 | Accept: -1,
29 | Ignore: "!whitespace",
30 | },
31 | ActionRow{ // S2
32 | Accept: 0,
33 | Ignore: "",
34 | },
35 | ActionRow{ // S3
36 | Accept: 0,
37 | Ignore: "",
38 | },
39 | ActionRow{ // S4
40 | Accept: 19,
41 | Ignore: "",
42 | },
43 | ActionRow{ // S5
44 | Accept: 4,
45 | Ignore: "",
46 | },
47 | ActionRow{ // S6
48 | Accept: 23,
49 | Ignore: "",
50 | },
51 | ActionRow{ // S7
52 | Accept: 5,
53 | Ignore: "",
54 | },
55 | ActionRow{ // S8
56 | Accept: 21,
57 | Ignore: "",
58 | },
59 | ActionRow{ // S9
60 | Accept: 23,
61 | Ignore: "",
62 | },
63 | ActionRow{ // S10
64 | Accept: 8,
65 | Ignore: "",
66 | },
67 | ActionRow{ // S11
68 | Accept: 8,
69 | Ignore: "",
70 | },
71 | ActionRow{ // S12
72 | Accept: 26,
73 | Ignore: "",
74 | },
75 | ActionRow{ // S13
76 | Accept: 24,
77 | Ignore: "",
78 | },
79 | ActionRow{ // S14
80 | Accept: 20,
81 | Ignore: "",
82 | },
83 | ActionRow{ // S15
84 | Accept: 2,
85 | Ignore: "",
86 | },
87 | ActionRow{ // S16
88 | Accept: 7,
89 | Ignore: "",
90 | },
91 | ActionRow{ // S17
92 | Accept: 7,
93 | Ignore: "",
94 | },
95 | ActionRow{ // S18
96 | Accept: 0,
97 | Ignore: "",
98 | },
99 | ActionRow{ // S19
100 | Accept: 7,
101 | Ignore: "",
102 | },
103 | ActionRow{ // S20
104 | Accept: 7,
105 | Ignore: "",
106 | },
107 | ActionRow{ // S21
108 | Accept: 7,
109 | Ignore: "",
110 | },
111 | ActionRow{ // S22
112 | Accept: 7,
113 | Ignore: "",
114 | },
115 | ActionRow{ // S23
116 | Accept: 7,
117 | Ignore: "",
118 | },
119 | ActionRow{ // S24
120 | Accept: 7,
121 | Ignore: "",
122 | },
123 | ActionRow{ // S25
124 | Accept: 7,
125 | Ignore: "",
126 | },
127 | ActionRow{ // S26
128 | Accept: 18,
129 | Ignore: "",
130 | },
131 | ActionRow{ // S27
132 | Accept: 3,
133 | Ignore: "",
134 | },
135 | ActionRow{ // S28
136 | Accept: 22,
137 | Ignore: "",
138 | },
139 | ActionRow{ // S29
140 | Accept: 0,
141 | Ignore: "",
142 | },
143 | ActionRow{ // S30
144 | Accept: 0,
145 | Ignore: "",
146 | },
147 | ActionRow{ // S31
148 | Accept: 0,
149 | Ignore: "",
150 | },
151 | ActionRow{ // S32
152 | Accept: 0,
153 | Ignore: "",
154 | },
155 | ActionRow{ // S33
156 | Accept: 8,
157 | Ignore: "",
158 | },
159 | ActionRow{ // S34
160 | Accept: 7,
161 | Ignore: "",
162 | },
163 | ActionRow{ // S35
164 | Accept: 22,
165 | Ignore: "",
166 | },
167 | ActionRow{ // S36
168 | Accept: 7,
169 | Ignore: "",
170 | },
171 | ActionRow{ // S37
172 | Accept: 7,
173 | Ignore: "",
174 | },
175 | ActionRow{ // S38
176 | Accept: 7,
177 | Ignore: "",
178 | },
179 | ActionRow{ // S39
180 | Accept: 7,
181 | Ignore: "",
182 | },
183 | ActionRow{ // S40
184 | Accept: 7,
185 | Ignore: "",
186 | },
187 | ActionRow{ // S41
188 | Accept: 13,
189 | Ignore: "",
190 | },
191 | ActionRow{ // S42
192 | Accept: 7,
193 | Ignore: "",
194 | },
195 | ActionRow{ // S43
196 | Accept: 7,
197 | Ignore: "",
198 | },
199 | ActionRow{ // S44
200 | Accept: 7,
201 | Ignore: "",
202 | },
203 | ActionRow{ // S45
204 | Accept: 7,
205 | Ignore: "",
206 | },
207 | ActionRow{ // S46
208 | Accept: 0,
209 | Ignore: "",
210 | },
211 | ActionRow{ // S47
212 | Accept: 0,
213 | Ignore: "",
214 | },
215 | ActionRow{ // S48
216 | Accept: -1,
217 | Ignore: "!comment",
218 | },
219 | ActionRow{ // S49
220 | Accept: 6,
221 | Ignore: "",
222 | },
223 | ActionRow{ // S50
224 | Accept: 7,
225 | Ignore: "",
226 | },
227 | ActionRow{ // S51
228 | Accept: 7,
229 | Ignore: "",
230 | },
231 | ActionRow{ // S52
232 | Accept: 11,
233 | Ignore: "",
234 | },
235 | ActionRow{ // S53
236 | Accept: 7,
237 | Ignore: "",
238 | },
239 | ActionRow{ // S54
240 | Accept: 7,
241 | Ignore: "",
242 | },
243 | ActionRow{ // S55
244 | Accept: 25,
245 | Ignore: "",
246 | },
247 | ActionRow{ // S56
248 | Accept: 7,
249 | Ignore: "",
250 | },
251 | ActionRow{ // S57
252 | Accept: 7,
253 | Ignore: "",
254 | },
255 | ActionRow{ // S58
256 | Accept: 16,
257 | Ignore: "",
258 | },
259 | ActionRow{ // S59
260 | Accept: 7,
261 | Ignore: "",
262 | },
263 | ActionRow{ // S60
264 | Accept: -1,
265 | Ignore: "!comment",
266 | },
267 | ActionRow{ // S61
268 | Accept: 7,
269 | Ignore: "",
270 | },
271 | ActionRow{ // S62
272 | Accept: 10,
273 | Ignore: "",
274 | },
275 | ActionRow{ // S63
276 | Accept: 7,
277 | Ignore: "",
278 | },
279 | ActionRow{ // S64
280 | Accept: 12,
281 | Ignore: "",
282 | },
283 | ActionRow{ // S65
284 | Accept: 7,
285 | Ignore: "",
286 | },
287 | ActionRow{ // S66
288 | Accept: 7,
289 | Ignore: "",
290 | },
291 | ActionRow{ // S67
292 | Accept: 7,
293 | Ignore: "",
294 | },
295 | ActionRow{ // S68
296 | Accept: 9,
297 | Ignore: "",
298 | },
299 | ActionRow{ // S69
300 | Accept: 14,
301 | Ignore: "",
302 | },
303 | ActionRow{ // S70
304 | Accept: 7,
305 | Ignore: "",
306 | },
307 | ActionRow{ // S71
308 | Accept: 17,
309 | Ignore: "",
310 | },
311 | ActionRow{ // S72
312 | Accept: 7,
313 | Ignore: "",
314 | },
315 | ActionRow{ // S73
316 | Accept: 15,
317 | Ignore: "",
318 | },
319 | }
320 |
--------------------------------------------------------------------------------
/src/lexer/lexer.go:
--------------------------------------------------------------------------------
1 | // Code generated by gocc; DO NOT EDIT.
2 |
3 | package lexer
4 |
5 | import (
6 | "os"
7 | "unicode/utf8"
8 |
9 | "pogo/src/token"
10 | )
11 |
12 | const (
13 | NoState = -1
14 | NumStates = 74
15 | NumSymbols = 96
16 | )
17 |
18 | type Lexer struct {
19 | src []byte
20 | pos int
21 | line int
22 | column int
23 | Context token.Context
24 | }
25 |
26 | func NewLexer(src []byte) *Lexer {
27 | lexer := &Lexer{
28 | src: src,
29 | pos: 0,
30 | line: 1,
31 | column: 1,
32 | Context: nil,
33 | }
34 | return lexer
35 | }
36 |
37 | // SourceContext is a simple instance of a token.Context which
38 | // contains the name of the source file.
39 | type SourceContext struct {
40 | Filepath string
41 | }
42 |
43 | func (s *SourceContext) Source() string {
44 | return s.Filepath
45 | }
46 |
47 | func NewLexerFile(fpath string) (*Lexer, error) {
48 | src, err := os.ReadFile(fpath)
49 | if err != nil {
50 | return nil, err
51 | }
52 | lexer := NewLexer(src)
53 | lexer.Context = &SourceContext{Filepath: fpath}
54 | return lexer, nil
55 | }
56 |
57 | func (l *Lexer) Scan() (tok *token.Token) {
58 | tok = &token.Token{}
59 | if l.pos >= len(l.src) {
60 | tok.Type = token.EOF
61 | tok.Pos.Offset, tok.Pos.Line, tok.Pos.Column = l.pos, l.line, l.column
62 | tok.Pos.Context = l.Context
63 | return
64 | }
65 | start, startLine, startColumn, end := l.pos, l.line, l.column, 0
66 | tok.Type = token.INVALID
67 | state, rune1, size := 0, rune(-1), 0
68 | for state != -1 {
69 | if l.pos >= len(l.src) {
70 | rune1 = -1
71 | } else {
72 | rune1, size = utf8.DecodeRune(l.src[l.pos:])
73 | l.pos += size
74 | }
75 |
76 | nextState := -1
77 | if rune1 != -1 {
78 | nextState = TransTab[state](rune1)
79 | }
80 | state = nextState
81 |
82 | if state != -1 {
83 |
84 | switch rune1 {
85 | case '\n':
86 | l.line++
87 | l.column = 1
88 | case '\r':
89 | l.column = 1
90 | case '\t':
91 | l.column += 4
92 | default:
93 | l.column++
94 | }
95 |
96 | switch {
97 | case ActTab[state].Accept != -1:
98 | tok.Type = ActTab[state].Accept
99 | end = l.pos
100 | case ActTab[state].Ignore != "":
101 | start, startLine, startColumn = l.pos, l.line, l.column
102 | state = 0
103 | if start >= len(l.src) {
104 | tok.Type = token.EOF
105 | }
106 |
107 | }
108 | } else {
109 | if tok.Type == token.INVALID {
110 | end = l.pos
111 | }
112 | }
113 | }
114 | if end > start {
115 | l.pos = end
116 | tok.Lit = l.src[start:end]
117 | } else {
118 | tok.Lit = []byte{}
119 | }
120 | tok.Pos.Offset, tok.Pos.Line, tok.Pos.Column = start, startLine, startColumn
121 | tok.Pos.Context = l.Context
122 |
123 | return
124 | }
125 |
126 | func (l *Lexer) Reset() {
127 | l.pos = 0
128 | }
129 |
130 | /*
131 | Lexer symbols:
132 | 0: ';'
133 | 1: ','
134 | 2: 'i'
135 | 3: 'n'
136 | 4: 't'
137 | 5: 'f'
138 | 6: 'l'
139 | 7: 'o'
140 | 8: 'a'
141 | 9: 't'
142 | 10: 'i'
143 | 11: 'f'
144 | 12: 'e'
145 | 13: 'l'
146 | 14: 's'
147 | 15: 'e'
148 | 16: 'w'
149 | 17: 'h'
150 | 18: 'i'
151 | 19: 'l'
152 | 20: 'e'
153 | 21: 'p'
154 | 22: 'r'
155 | 23: 'i'
156 | 24: 'n'
157 | 25: 't'
158 | 26: 'f'
159 | 27: 'u'
160 | 28: 'n'
161 | 29: 'c'
162 | 30: 'p'
163 | 31: 'r'
164 | 32: 'o'
165 | 33: 'g'
166 | 34: 'r'
167 | 35: 'a'
168 | 36: 'm'
169 | 37: 'b'
170 | 38: 'e'
171 | 39: 'g'
172 | 40: 'i'
173 | 41: 'n'
174 | 42: 'e'
175 | 43: 'n'
176 | 44: 'd'
177 | 45: 'v'
178 | 46: 'a'
179 | 47: 'r'
180 | 48: '='
181 | 49: '='
182 | 50: '!'
183 | 51: '='
184 | 52: '<'
185 | 53: '>'
186 | 54: '+'
187 | 55: '-'
188 | 56: '*'
189 | 57: '/'
190 | 58: '='
191 | 59: ':'
192 | 60: '{'
193 | 61: '}'
194 | 62: '('
195 | 63: ')'
196 | 64: '0'
197 | 65: '.'
198 | 66: '_'
199 | 67: '`'
200 | 68: '`'
201 | 69: '\'
202 | 70: 'n'
203 | 71: '\'
204 | 72: 'r'
205 | 73: '\'
206 | 74: 't'
207 | 75: '"'
208 | 76: '\'
209 | 77: '"'
210 | 78: '"'
211 | 79: '/'
212 | 80: '/'
213 | 81: '\n'
214 | 82: '/'
215 | 83: '*'
216 | 84: '*'
217 | 85: '*'
218 | 86: '/'
219 | 87: ' '
220 | 88: '\t'
221 | 89: '\n'
222 | 90: '\r'
223 | 91: '1'-'9'
224 | 92: 'a'-'z'
225 | 93: 'A'-'Z'
226 | 94: '0'-'9'
227 | 95: .
228 | */
229 |
--------------------------------------------------------------------------------
/src/lexer/transitiontable.go:
--------------------------------------------------------------------------------
1 | // Code generated by gocc; DO NOT EDIT.
2 |
3 | package lexer
4 |
5 | /*
6 | Let s be the current state
7 | Let r be the current input rune
8 | transitionTable[s](r) returns the next state.
9 | */
10 | type TransitionTable [NumStates]func(rune) int
11 |
12 | var TransTab = TransitionTable{
13 | // S0
14 | func(r rune) int {
15 | switch {
16 | case r == 9: // ['\t','\t']
17 | return 1
18 | case r == 10: // ['\n','\n']
19 | return 1
20 | case r == 13: // ['\r','\r']
21 | return 1
22 | case r == 32: // [' ',' ']
23 | return 1
24 | case r == 33: // ['!','!']
25 | return 2
26 | case r == 34: // ['"','"']
27 | return 3
28 | case r == 40: // ['(','(']
29 | return 4
30 | case r == 41: // [')',')']
31 | return 5
32 | case r == 42: // ['*','*']
33 | return 6
34 | case r == 43: // ['+','+']
35 | return 7
36 | case r == 44: // [',',',']
37 | return 8
38 | case r == 45: // ['-','-']
39 | return 7
40 | case r == 47: // ['/','/']
41 | return 9
42 | case r == 48: // ['0','0']
43 | return 10
44 | case 49 <= r && r <= 57: // ['1','9']
45 | return 11
46 | case r == 58: // [':',':']
47 | return 12
48 | case r == 59: // [';',';']
49 | return 13
50 | case r == 60: // ['<','<']
51 | return 14
52 | case r == 61: // ['=','=']
53 | return 15
54 | case r == 62: // ['>','>']
55 | return 14
56 | case 65 <= r && r <= 90: // ['A','Z']
57 | return 16
58 | case r == 95: // ['_','_']
59 | return 17
60 | case r == 96: // ['`','`']
61 | return 18
62 | case r == 97: // ['a','a']
63 | return 16
64 | case r == 98: // ['b','b']
65 | return 19
66 | case 99 <= r && r <= 100: // ['c','d']
67 | return 16
68 | case r == 101: // ['e','e']
69 | return 20
70 | case r == 102: // ['f','f']
71 | return 21
72 | case 103 <= r && r <= 104: // ['g','h']
73 | return 16
74 | case r == 105: // ['i','i']
75 | return 22
76 | case 106 <= r && r <= 111: // ['j','o']
77 | return 16
78 | case r == 112: // ['p','p']
79 | return 23
80 | case 113 <= r && r <= 117: // ['q','u']
81 | return 16
82 | case r == 118: // ['v','v']
83 | return 24
84 | case r == 119: // ['w','w']
85 | return 25
86 | case 120 <= r && r <= 122: // ['x','z']
87 | return 16
88 | case r == 123: // ['{','{']
89 | return 26
90 | case r == 125: // ['}','}']
91 | return 27
92 | }
93 | return NoState
94 | },
95 | // S1
96 | func(r rune) int {
97 | switch {
98 | }
99 | return NoState
100 | },
101 | // S2
102 | func(r rune) int {
103 | switch {
104 | case r == 61: // ['=','=']
105 | return 14
106 | }
107 | return NoState
108 | },
109 | // S3
110 | func(r rune) int {
111 | switch {
112 | case r == 34: // ['"','"']
113 | return 28
114 | case r == 92: // ['\','\']
115 | return 29
116 | default:
117 | return 3
118 | }
119 | },
120 | // S4
121 | func(r rune) int {
122 | switch {
123 | }
124 | return NoState
125 | },
126 | // S5
127 | func(r rune) int {
128 | switch {
129 | }
130 | return NoState
131 | },
132 | // S6
133 | func(r rune) int {
134 | switch {
135 | }
136 | return NoState
137 | },
138 | // S7
139 | func(r rune) int {
140 | switch {
141 | }
142 | return NoState
143 | },
144 | // S8
145 | func(r rune) int {
146 | switch {
147 | }
148 | return NoState
149 | },
150 | // S9
151 | func(r rune) int {
152 | switch {
153 | case r == 42: // ['*','*']
154 | return 30
155 | case r == 47: // ['/','/']
156 | return 31
157 | }
158 | return NoState
159 | },
160 | // S10
161 | func(r rune) int {
162 | switch {
163 | case r == 46: // ['.','.']
164 | return 32
165 | }
166 | return NoState
167 | },
168 | // S11
169 | func(r rune) int {
170 | switch {
171 | case r == 46: // ['.','.']
172 | return 32
173 | case 48 <= r && r <= 57: // ['0','9']
174 | return 33
175 | }
176 | return NoState
177 | },
178 | // S12
179 | func(r rune) int {
180 | switch {
181 | }
182 | return NoState
183 | },
184 | // S13
185 | func(r rune) int {
186 | switch {
187 | }
188 | return NoState
189 | },
190 | // S14
191 | func(r rune) int {
192 | switch {
193 | }
194 | return NoState
195 | },
196 | // S15
197 | func(r rune) int {
198 | switch {
199 | case r == 61: // ['=','=']
200 | return 14
201 | }
202 | return NoState
203 | },
204 | // S16
205 | func(r rune) int {
206 | switch {
207 | case 48 <= r && r <= 57: // ['0','9']
208 | return 34
209 | case 65 <= r && r <= 90: // ['A','Z']
210 | return 16
211 | case r == 95: // ['_','_']
212 | return 17
213 | case 97 <= r && r <= 122: // ['a','z']
214 | return 16
215 | }
216 | return NoState
217 | },
218 | // S17
219 | func(r rune) int {
220 | switch {
221 | case 48 <= r && r <= 57: // ['0','9']
222 | return 34
223 | case 65 <= r && r <= 90: // ['A','Z']
224 | return 16
225 | case r == 95: // ['_','_']
226 | return 17
227 | case 97 <= r && r <= 122: // ['a','z']
228 | return 16
229 | }
230 | return NoState
231 | },
232 | // S18
233 | func(r rune) int {
234 | switch {
235 | case r == 96: // ['`','`']
236 | return 35
237 | default:
238 | return 18
239 | }
240 | },
241 | // S19
242 | func(r rune) int {
243 | switch {
244 | case 48 <= r && r <= 57: // ['0','9']
245 | return 34
246 | case 65 <= r && r <= 90: // ['A','Z']
247 | return 16
248 | case r == 95: // ['_','_']
249 | return 17
250 | case 97 <= r && r <= 100: // ['a','d']
251 | return 16
252 | case r == 101: // ['e','e']
253 | return 36
254 | case 102 <= r && r <= 122: // ['f','z']
255 | return 16
256 | }
257 | return NoState
258 | },
259 | // S20
260 | func(r rune) int {
261 | switch {
262 | case 48 <= r && r <= 57: // ['0','9']
263 | return 34
264 | case 65 <= r && r <= 90: // ['A','Z']
265 | return 16
266 | case r == 95: // ['_','_']
267 | return 17
268 | case 97 <= r && r <= 107: // ['a','k']
269 | return 16
270 | case r == 108: // ['l','l']
271 | return 37
272 | case r == 109: // ['m','m']
273 | return 16
274 | case r == 110: // ['n','n']
275 | return 38
276 | case 111 <= r && r <= 122: // ['o','z']
277 | return 16
278 | }
279 | return NoState
280 | },
281 | // S21
282 | func(r rune) int {
283 | switch {
284 | case 48 <= r && r <= 57: // ['0','9']
285 | return 34
286 | case 65 <= r && r <= 90: // ['A','Z']
287 | return 16
288 | case r == 95: // ['_','_']
289 | return 17
290 | case 97 <= r && r <= 107: // ['a','k']
291 | return 16
292 | case r == 108: // ['l','l']
293 | return 39
294 | case 109 <= r && r <= 116: // ['m','t']
295 | return 16
296 | case r == 117: // ['u','u']
297 | return 40
298 | case 118 <= r && r <= 122: // ['v','z']
299 | return 16
300 | }
301 | return NoState
302 | },
303 | // S22
304 | func(r rune) int {
305 | switch {
306 | case 48 <= r && r <= 57: // ['0','9']
307 | return 34
308 | case 65 <= r && r <= 90: // ['A','Z']
309 | return 16
310 | case r == 95: // ['_','_']
311 | return 17
312 | case 97 <= r && r <= 101: // ['a','e']
313 | return 16
314 | case r == 102: // ['f','f']
315 | return 41
316 | case 103 <= r && r <= 109: // ['g','m']
317 | return 16
318 | case r == 110: // ['n','n']
319 | return 42
320 | case 111 <= r && r <= 122: // ['o','z']
321 | return 16
322 | }
323 | return NoState
324 | },
325 | // S23
326 | func(r rune) int {
327 | switch {
328 | case 48 <= r && r <= 57: // ['0','9']
329 | return 34
330 | case 65 <= r && r <= 90: // ['A','Z']
331 | return 16
332 | case r == 95: // ['_','_']
333 | return 17
334 | case 97 <= r && r <= 113: // ['a','q']
335 | return 16
336 | case r == 114: // ['r','r']
337 | return 43
338 | case 115 <= r && r <= 122: // ['s','z']
339 | return 16
340 | }
341 | return NoState
342 | },
343 | // S24
344 | func(r rune) int {
345 | switch {
346 | case 48 <= r && r <= 57: // ['0','9']
347 | return 34
348 | case 65 <= r && r <= 90: // ['A','Z']
349 | return 16
350 | case r == 95: // ['_','_']
351 | return 17
352 | case r == 97: // ['a','a']
353 | return 44
354 | case 98 <= r && r <= 122: // ['b','z']
355 | return 16
356 | }
357 | return NoState
358 | },
359 | // S25
360 | func(r rune) int {
361 | switch {
362 | case 48 <= r && r <= 57: // ['0','9']
363 | return 34
364 | case 65 <= r && r <= 90: // ['A','Z']
365 | return 16
366 | case r == 95: // ['_','_']
367 | return 17
368 | case 97 <= r && r <= 103: // ['a','g']
369 | return 16
370 | case r == 104: // ['h','h']
371 | return 45
372 | case 105 <= r && r <= 122: // ['i','z']
373 | return 16
374 | }
375 | return NoState
376 | },
377 | // S26
378 | func(r rune) int {
379 | switch {
380 | }
381 | return NoState
382 | },
383 | // S27
384 | func(r rune) int {
385 | switch {
386 | }
387 | return NoState
388 | },
389 | // S28
390 | func(r rune) int {
391 | switch {
392 | }
393 | return NoState
394 | },
395 | // S29
396 | func(r rune) int {
397 | switch {
398 | case r == 34: // ['"','"']
399 | return 3
400 | case r == 110: // ['n','n']
401 | return 46
402 | case r == 114: // ['r','r']
403 | return 46
404 | case r == 116: // ['t','t']
405 | return 46
406 | }
407 | return NoState
408 | },
409 | // S30
410 | func(r rune) int {
411 | switch {
412 | case r == 42: // ['*','*']
413 | return 47
414 | default:
415 | return 30
416 | }
417 | },
418 | // S31
419 | func(r rune) int {
420 | switch {
421 | case r == 10: // ['\n','\n']
422 | return 48
423 | default:
424 | return 31
425 | }
426 | },
427 | // S32
428 | func(r rune) int {
429 | switch {
430 | case 48 <= r && r <= 57: // ['0','9']
431 | return 49
432 | }
433 | return NoState
434 | },
435 | // S33
436 | func(r rune) int {
437 | switch {
438 | case 48 <= r && r <= 57: // ['0','9']
439 | return 33
440 | }
441 | return NoState
442 | },
443 | // S34
444 | func(r rune) int {
445 | switch {
446 | case 48 <= r && r <= 57: // ['0','9']
447 | return 34
448 | case 65 <= r && r <= 90: // ['A','Z']
449 | return 16
450 | case r == 95: // ['_','_']
451 | return 17
452 | case 97 <= r && r <= 122: // ['a','z']
453 | return 16
454 | }
455 | return NoState
456 | },
457 | // S35
458 | func(r rune) int {
459 | switch {
460 | }
461 | return NoState
462 | },
463 | // S36
464 | func(r rune) int {
465 | switch {
466 | case 48 <= r && r <= 57: // ['0','9']
467 | return 34
468 | case 65 <= r && r <= 90: // ['A','Z']
469 | return 16
470 | case r == 95: // ['_','_']
471 | return 17
472 | case 97 <= r && r <= 102: // ['a','f']
473 | return 16
474 | case r == 103: // ['g','g']
475 | return 50
476 | case 104 <= r && r <= 122: // ['h','z']
477 | return 16
478 | }
479 | return NoState
480 | },
481 | // S37
482 | func(r rune) int {
483 | switch {
484 | case 48 <= r && r <= 57: // ['0','9']
485 | return 34
486 | case 65 <= r && r <= 90: // ['A','Z']
487 | return 16
488 | case r == 95: // ['_','_']
489 | return 17
490 | case 97 <= r && r <= 114: // ['a','r']
491 | return 16
492 | case r == 115: // ['s','s']
493 | return 51
494 | case 116 <= r && r <= 122: // ['t','z']
495 | return 16
496 | }
497 | return NoState
498 | },
499 | // S38
500 | func(r rune) int {
501 | switch {
502 | case 48 <= r && r <= 57: // ['0','9']
503 | return 34
504 | case 65 <= r && r <= 90: // ['A','Z']
505 | return 16
506 | case r == 95: // ['_','_']
507 | return 17
508 | case 97 <= r && r <= 99: // ['a','c']
509 | return 16
510 | case r == 100: // ['d','d']
511 | return 52
512 | case 101 <= r && r <= 122: // ['e','z']
513 | return 16
514 | }
515 | return NoState
516 | },
517 | // S39
518 | func(r rune) int {
519 | switch {
520 | case 48 <= r && r <= 57: // ['0','9']
521 | return 34
522 | case 65 <= r && r <= 90: // ['A','Z']
523 | return 16
524 | case r == 95: // ['_','_']
525 | return 17
526 | case 97 <= r && r <= 110: // ['a','n']
527 | return 16
528 | case r == 111: // ['o','o']
529 | return 53
530 | case 112 <= r && r <= 122: // ['p','z']
531 | return 16
532 | }
533 | return NoState
534 | },
535 | // S40
536 | func(r rune) int {
537 | switch {
538 | case 48 <= r && r <= 57: // ['0','9']
539 | return 34
540 | case 65 <= r && r <= 90: // ['A','Z']
541 | return 16
542 | case r == 95: // ['_','_']
543 | return 17
544 | case 97 <= r && r <= 109: // ['a','m']
545 | return 16
546 | case r == 110: // ['n','n']
547 | return 54
548 | case 111 <= r && r <= 122: // ['o','z']
549 | return 16
550 | }
551 | return NoState
552 | },
553 | // S41
554 | func(r rune) int {
555 | switch {
556 | case 48 <= r && r <= 57: // ['0','9']
557 | return 34
558 | case 65 <= r && r <= 90: // ['A','Z']
559 | return 16
560 | case r == 95: // ['_','_']
561 | return 17
562 | case 97 <= r && r <= 122: // ['a','z']
563 | return 16
564 | }
565 | return NoState
566 | },
567 | // S42
568 | func(r rune) int {
569 | switch {
570 | case 48 <= r && r <= 57: // ['0','9']
571 | return 34
572 | case 65 <= r && r <= 90: // ['A','Z']
573 | return 16
574 | case r == 95: // ['_','_']
575 | return 17
576 | case 97 <= r && r <= 115: // ['a','s']
577 | return 16
578 | case r == 116: // ['t','t']
579 | return 55
580 | case 117 <= r && r <= 122: // ['u','z']
581 | return 16
582 | }
583 | return NoState
584 | },
585 | // S43
586 | func(r rune) int {
587 | switch {
588 | case 48 <= r && r <= 57: // ['0','9']
589 | return 34
590 | case 65 <= r && r <= 90: // ['A','Z']
591 | return 16
592 | case r == 95: // ['_','_']
593 | return 17
594 | case 97 <= r && r <= 104: // ['a','h']
595 | return 16
596 | case r == 105: // ['i','i']
597 | return 56
598 | case 106 <= r && r <= 110: // ['j','n']
599 | return 16
600 | case r == 111: // ['o','o']
601 | return 57
602 | case 112 <= r && r <= 122: // ['p','z']
603 | return 16
604 | }
605 | return NoState
606 | },
607 | // S44
608 | func(r rune) int {
609 | switch {
610 | case 48 <= r && r <= 57: // ['0','9']
611 | return 34
612 | case 65 <= r && r <= 90: // ['A','Z']
613 | return 16
614 | case r == 95: // ['_','_']
615 | return 17
616 | case 97 <= r && r <= 113: // ['a','q']
617 | return 16
618 | case r == 114: // ['r','r']
619 | return 58
620 | case 115 <= r && r <= 122: // ['s','z']
621 | return 16
622 | }
623 | return NoState
624 | },
625 | // S45
626 | func(r rune) int {
627 | switch {
628 | case 48 <= r && r <= 57: // ['0','9']
629 | return 34
630 | case 65 <= r && r <= 90: // ['A','Z']
631 | return 16
632 | case r == 95: // ['_','_']
633 | return 17
634 | case 97 <= r && r <= 104: // ['a','h']
635 | return 16
636 | case r == 105: // ['i','i']
637 | return 59
638 | case 106 <= r && r <= 122: // ['j','z']
639 | return 16
640 | }
641 | return NoState
642 | },
643 | // S46
644 | func(r rune) int {
645 | switch {
646 | case r == 34: // ['"','"']
647 | return 28
648 | case r == 92: // ['\','\']
649 | return 29
650 | default:
651 | return 3
652 | }
653 | },
654 | // S47
655 | func(r rune) int {
656 | switch {
657 | case r == 42: // ['*','*']
658 | return 47
659 | case r == 47: // ['/','/']
660 | return 60
661 | default:
662 | return 30
663 | }
664 | },
665 | // S48
666 | func(r rune) int {
667 | switch {
668 | }
669 | return NoState
670 | },
671 | // S49
672 | func(r rune) int {
673 | switch {
674 | case 48 <= r && r <= 57: // ['0','9']
675 | return 49
676 | }
677 | return NoState
678 | },
679 | // S50
680 | func(r rune) int {
681 | switch {
682 | case 48 <= r && r <= 57: // ['0','9']
683 | return 34
684 | case 65 <= r && r <= 90: // ['A','Z']
685 | return 16
686 | case r == 95: // ['_','_']
687 | return 17
688 | case 97 <= r && r <= 104: // ['a','h']
689 | return 16
690 | case r == 105: // ['i','i']
691 | return 61
692 | case 106 <= r && r <= 122: // ['j','z']
693 | return 16
694 | }
695 | return NoState
696 | },
697 | // S51
698 | func(r rune) int {
699 | switch {
700 | case 48 <= r && r <= 57: // ['0','9']
701 | return 34
702 | case 65 <= r && r <= 90: // ['A','Z']
703 | return 16
704 | case r == 95: // ['_','_']
705 | return 17
706 | case 97 <= r && r <= 100: // ['a','d']
707 | return 16
708 | case r == 101: // ['e','e']
709 | return 62
710 | case 102 <= r && r <= 122: // ['f','z']
711 | return 16
712 | }
713 | return NoState
714 | },
715 | // S52
716 | func(r rune) int {
717 | switch {
718 | case 48 <= r && r <= 57: // ['0','9']
719 | return 34
720 | case 65 <= r && r <= 90: // ['A','Z']
721 | return 16
722 | case r == 95: // ['_','_']
723 | return 17
724 | case 97 <= r && r <= 122: // ['a','z']
725 | return 16
726 | }
727 | return NoState
728 | },
729 | // S53
730 | func(r rune) int {
731 | switch {
732 | case 48 <= r && r <= 57: // ['0','9']
733 | return 34
734 | case 65 <= r && r <= 90: // ['A','Z']
735 | return 16
736 | case r == 95: // ['_','_']
737 | return 17
738 | case r == 97: // ['a','a']
739 | return 63
740 | case 98 <= r && r <= 122: // ['b','z']
741 | return 16
742 | }
743 | return NoState
744 | },
745 | // S54
746 | func(r rune) int {
747 | switch {
748 | case 48 <= r && r <= 57: // ['0','9']
749 | return 34
750 | case 65 <= r && r <= 90: // ['A','Z']
751 | return 16
752 | case r == 95: // ['_','_']
753 | return 17
754 | case 97 <= r && r <= 98: // ['a','b']
755 | return 16
756 | case r == 99: // ['c','c']
757 | return 64
758 | case 100 <= r && r <= 122: // ['d','z']
759 | return 16
760 | }
761 | return NoState
762 | },
763 | // S55
764 | func(r rune) int {
765 | switch {
766 | case 48 <= r && r <= 57: // ['0','9']
767 | return 34
768 | case 65 <= r && r <= 90: // ['A','Z']
769 | return 16
770 | case r == 95: // ['_','_']
771 | return 17
772 | case 97 <= r && r <= 122: // ['a','z']
773 | return 16
774 | }
775 | return NoState
776 | },
777 | // S56
778 | func(r rune) int {
779 | switch {
780 | case 48 <= r && r <= 57: // ['0','9']
781 | return 34
782 | case 65 <= r && r <= 90: // ['A','Z']
783 | return 16
784 | case r == 95: // ['_','_']
785 | return 17
786 | case 97 <= r && r <= 109: // ['a','m']
787 | return 16
788 | case r == 110: // ['n','n']
789 | return 65
790 | case 111 <= r && r <= 122: // ['o','z']
791 | return 16
792 | }
793 | return NoState
794 | },
795 | // S57
796 | func(r rune) int {
797 | switch {
798 | case 48 <= r && r <= 57: // ['0','9']
799 | return 34
800 | case 65 <= r && r <= 90: // ['A','Z']
801 | return 16
802 | case r == 95: // ['_','_']
803 | return 17
804 | case 97 <= r && r <= 102: // ['a','f']
805 | return 16
806 | case r == 103: // ['g','g']
807 | return 66
808 | case 104 <= r && r <= 122: // ['h','z']
809 | return 16
810 | }
811 | return NoState
812 | },
813 | // S58
814 | func(r rune) int {
815 | switch {
816 | case 48 <= r && r <= 57: // ['0','9']
817 | return 34
818 | case 65 <= r && r <= 90: // ['A','Z']
819 | return 16
820 | case r == 95: // ['_','_']
821 | return 17
822 | case 97 <= r && r <= 122: // ['a','z']
823 | return 16
824 | }
825 | return NoState
826 | },
827 | // S59
828 | func(r rune) int {
829 | switch {
830 | case 48 <= r && r <= 57: // ['0','9']
831 | return 34
832 | case 65 <= r && r <= 90: // ['A','Z']
833 | return 16
834 | case r == 95: // ['_','_']
835 | return 17
836 | case 97 <= r && r <= 107: // ['a','k']
837 | return 16
838 | case r == 108: // ['l','l']
839 | return 67
840 | case 109 <= r && r <= 122: // ['m','z']
841 | return 16
842 | }
843 | return NoState
844 | },
845 | // S60
846 | func(r rune) int {
847 | switch {
848 | }
849 | return NoState
850 | },
851 | // S61
852 | func(r rune) int {
853 | switch {
854 | case 48 <= r && r <= 57: // ['0','9']
855 | return 34
856 | case 65 <= r && r <= 90: // ['A','Z']
857 | return 16
858 | case r == 95: // ['_','_']
859 | return 17
860 | case 97 <= r && r <= 109: // ['a','m']
861 | return 16
862 | case r == 110: // ['n','n']
863 | return 68
864 | case 111 <= r && r <= 122: // ['o','z']
865 | return 16
866 | }
867 | return NoState
868 | },
869 | // S62
870 | func(r rune) int {
871 | switch {
872 | case 48 <= r && r <= 57: // ['0','9']
873 | return 34
874 | case 65 <= r && r <= 90: // ['A','Z']
875 | return 16
876 | case r == 95: // ['_','_']
877 | return 17
878 | case 97 <= r && r <= 122: // ['a','z']
879 | return 16
880 | }
881 | return NoState
882 | },
883 | // S63
884 | func(r rune) int {
885 | switch {
886 | case 48 <= r && r <= 57: // ['0','9']
887 | return 34
888 | case 65 <= r && r <= 90: // ['A','Z']
889 | return 16
890 | case r == 95: // ['_','_']
891 | return 17
892 | case 97 <= r && r <= 115: // ['a','s']
893 | return 16
894 | case r == 116: // ['t','t']
895 | return 55
896 | case 117 <= r && r <= 122: // ['u','z']
897 | return 16
898 | }
899 | return NoState
900 | },
901 | // S64
902 | func(r rune) int {
903 | switch {
904 | case 48 <= r && r <= 57: // ['0','9']
905 | return 34
906 | case 65 <= r && r <= 90: // ['A','Z']
907 | return 16
908 | case r == 95: // ['_','_']
909 | return 17
910 | case 97 <= r && r <= 122: // ['a','z']
911 | return 16
912 | }
913 | return NoState
914 | },
915 | // S65
916 | func(r rune) int {
917 | switch {
918 | case 48 <= r && r <= 57: // ['0','9']
919 | return 34
920 | case 65 <= r && r <= 90: // ['A','Z']
921 | return 16
922 | case r == 95: // ['_','_']
923 | return 17
924 | case 97 <= r && r <= 115: // ['a','s']
925 | return 16
926 | case r == 116: // ['t','t']
927 | return 69
928 | case 117 <= r && r <= 122: // ['u','z']
929 | return 16
930 | }
931 | return NoState
932 | },
933 | // S66
934 | func(r rune) int {
935 | switch {
936 | case 48 <= r && r <= 57: // ['0','9']
937 | return 34
938 | case 65 <= r && r <= 90: // ['A','Z']
939 | return 16
940 | case r == 95: // ['_','_']
941 | return 17
942 | case 97 <= r && r <= 113: // ['a','q']
943 | return 16
944 | case r == 114: // ['r','r']
945 | return 70
946 | case 115 <= r && r <= 122: // ['s','z']
947 | return 16
948 | }
949 | return NoState
950 | },
951 | // S67
952 | func(r rune) int {
953 | switch {
954 | case 48 <= r && r <= 57: // ['0','9']
955 | return 34
956 | case 65 <= r && r <= 90: // ['A','Z']
957 | return 16
958 | case r == 95: // ['_','_']
959 | return 17
960 | case 97 <= r && r <= 100: // ['a','d']
961 | return 16
962 | case r == 101: // ['e','e']
963 | return 71
964 | case 102 <= r && r <= 122: // ['f','z']
965 | return 16
966 | }
967 | return NoState
968 | },
969 | // S68
970 | func(r rune) int {
971 | switch {
972 | case 48 <= r && r <= 57: // ['0','9']
973 | return 34
974 | case 65 <= r && r <= 90: // ['A','Z']
975 | return 16
976 | case r == 95: // ['_','_']
977 | return 17
978 | case 97 <= r && r <= 122: // ['a','z']
979 | return 16
980 | }
981 | return NoState
982 | },
983 | // S69
984 | func(r rune) int {
985 | switch {
986 | case 48 <= r && r <= 57: // ['0','9']
987 | return 34
988 | case 65 <= r && r <= 90: // ['A','Z']
989 | return 16
990 | case r == 95: // ['_','_']
991 | return 17
992 | case 97 <= r && r <= 122: // ['a','z']
993 | return 16
994 | }
995 | return NoState
996 | },
997 | // S70
998 | func(r rune) int {
999 | switch {
1000 | case 48 <= r && r <= 57: // ['0','9']
1001 | return 34
1002 | case 65 <= r && r <= 90: // ['A','Z']
1003 | return 16
1004 | case r == 95: // ['_','_']
1005 | return 17
1006 | case r == 97: // ['a','a']
1007 | return 72
1008 | case 98 <= r && r <= 122: // ['b','z']
1009 | return 16
1010 | }
1011 | return NoState
1012 | },
1013 | // S71
1014 | func(r rune) int {
1015 | switch {
1016 | case 48 <= r && r <= 57: // ['0','9']
1017 | return 34
1018 | case 65 <= r && r <= 90: // ['A','Z']
1019 | return 16
1020 | case r == 95: // ['_','_']
1021 | return 17
1022 | case 97 <= r && r <= 122: // ['a','z']
1023 | return 16
1024 | }
1025 | return NoState
1026 | },
1027 | // S72
1028 | func(r rune) int {
1029 | switch {
1030 | case 48 <= r && r <= 57: // ['0','9']
1031 | return 34
1032 | case 65 <= r && r <= 90: // ['A','Z']
1033 | return 16
1034 | case r == 95: // ['_','_']
1035 | return 17
1036 | case 97 <= r && r <= 108: // ['a','l']
1037 | return 16
1038 | case r == 109: // ['m','m']
1039 | return 73
1040 | case 110 <= r && r <= 122: // ['n','z']
1041 | return 16
1042 | }
1043 | return NoState
1044 | },
1045 | // S73
1046 | func(r rune) int {
1047 | switch {
1048 | case 48 <= r && r <= 57: // ['0','9']
1049 | return 34
1050 | case 65 <= r && r <= 90: // ['A','Z']
1051 | return 16
1052 | case r == 95: // ['_','_']
1053 | return 17
1054 | case 97 <= r && r <= 122: // ['a','z']
1055 | return 16
1056 | }
1057 | return NoState
1058 | },
1059 | }
1060 |
--------------------------------------------------------------------------------
/src/parser/parser.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "fmt"
5 | "pogo/src/lexer"
6 | "pogo/src/semantic"
7 | "pogo/src/shared"
8 | "pogo/src/token"
9 | )
10 |
11 | type Parser struct {
12 | lexer *lexer.Lexer
13 | curr *token.Token
14 | SymbolTable *semantic.SymbolTable
15 | CodeGenerator *semantic.QuadrupleList
16 | }
17 |
18 | func NewParser(l *lexer.Lexer) *Parser {
19 | p := &Parser{
20 | lexer: l,
21 | SymbolTable: semantic.NewSymbolTable(),
22 | CodeGenerator: semantic.NewQuadrupleList(),
23 | }
24 | p.next()
25 | return p
26 | }
27 |
28 | func (p *Parser) ParseProgram() error {
29 | p.CodeGenerator.HandleProgramStart()
30 |
31 | if err := p.parseProgramName(); err != nil {
32 | return err
33 | }
34 |
35 | if err := p.parseVarDeclarationSection(false); err != nil {
36 | return err
37 | }
38 |
39 | if err := p.parseFunctionListOpt(); err != nil {
40 | return err
41 | }
42 |
43 | if err := p.parseMainSection(); err != nil {
44 | return err
45 | }
46 | // p.SymbolTable.PrettyPrint()
47 | //p.CodeGenerator.Print()
48 | //p.CodeGenerator.PrintStacks()
49 |
50 | return nil
51 | }
52 |
53 | func (p *Parser) parseProgramName() error {
54 | if err := p.expect(token.TokMap.Type("kwdProgram")); err != nil {
55 | return err
56 | }
57 | if err := p.expect(token.TokMap.Type("id")); err != nil {
58 | return err
59 | }
60 | return p.expect(token.TokMap.Type("terminator"))
61 | }
62 |
63 | func (p *Parser) parseVarDeclarationSection(isFunction bool) error {
64 | if p.curr.Type != token.TokMap.Type("kwdVars") {
65 | if p.curr.Type != token.TokMap.Type("kwdFunc") && p.curr.Type != token.TokMap.Type("kwdBegin") && !isFunction {
66 | return fmt.Errorf("line %d: unexpected token '%s', expected 'var', 'func', or 'begin'", p.curr.Line, p.curr.Lit)
67 | }
68 | return nil
69 | }
70 |
71 | for p.curr.Type == token.TokMap.Type("kwdVars") {
72 | if err := p.parseVarDeclaration(isFunction); err != nil {
73 | return err
74 | }
75 | }
76 |
77 | return nil
78 | }
79 |
80 | func (p *Parser) parseVarDeclaration(isFunction bool) error {
81 | if err := p.expect(token.TokMap.Type("kwdVars")); err != nil {
82 | return err
83 | }
84 |
85 | if err := p.parseVarList(); err != nil {
86 | return err
87 | }
88 |
89 | // process varType in a later process
90 |
91 | if err := p.expect(token.TokMap.Type("terminator")); err != nil {
92 | return err
93 | }
94 |
95 | return p.parseVarDeclarationSection(isFunction)
96 | }
97 |
98 | func (p *Parser) parseVarList() error {
99 | currentVars := make([]string, 0)
100 | initialVar := string(p.curr.Lit)
101 | currentVars = append(currentVars, initialVar)
102 | if err := p.expect(token.TokMap.Type("id")); err != nil {
103 | return err
104 | }
105 | // Append id into currentVars
106 |
107 | for p.curr.Type == token.TokMap.Type("repeatTerminator") {
108 | p.next()
109 | currentVars = append(currentVars, string(p.curr.Lit))
110 | if err := p.expect(token.TokMap.Type("id")); err != nil {
111 | return err
112 | }
113 | }
114 |
115 | if err := p.expect(token.TokMap.Type("typeAssignOp")); err != nil {
116 | return err
117 | }
118 |
119 | currType := string(p.curr.Lit)
120 | semType, err := p.returnSemanticType(currType)
121 | if err != nil {
122 | return err
123 | }
124 |
125 | if err := p.addVariablesToSymbolTable(semType, currentVars); err != nil {
126 | return err
127 | }
128 |
129 | _, err = p.parseType()
130 |
131 | if err != nil {
132 | return err
133 | }
134 |
135 | return nil
136 | }
137 |
138 | func (p *Parser) parseType() (string, error) {
139 | currType := p.curr.Lit
140 | if err := p.expect(token.TokMap.Type("type")); err != nil {
141 | return "", err
142 | }
143 | return string(currType), nil
144 | }
145 |
146 | func (p *Parser) parseFunctionListOpt() error {
147 | if p.curr.Type != token.TokMap.Type("kwdFunc") {
148 | return nil
149 | }
150 |
151 | if p.curr.Type != token.TokMap.Type("kwdFunc") {
152 | if p.curr.Type != token.TokMap.Type("kwdBegin") {
153 | return fmt.Errorf("line %d: unexpected token '%s', expected 'var', 'func', or 'begin'",
154 | p.curr.Line, p.curr.Lit)
155 | }
156 | return nil
157 | }
158 |
159 | if err := p.parseFunctionList(); err != nil {
160 | return err
161 | }
162 |
163 | return nil
164 | }
165 |
166 | func (p *Parser) parseFunctionList() error {
167 |
168 | for p.curr.Type == token.TokMap.Type("kwdFunc") {
169 | if err := p.parseFunction(); err != nil {
170 | return err
171 | }
172 | }
173 |
174 | return nil
175 | }
176 |
177 | func (p *Parser) parseFunction() error {
178 |
179 | if err := p.expect(token.TokMap.Type("kwdFunc")); err != nil {
180 | return err
181 | }
182 |
183 | functionId := p.curr.Lit
184 |
185 | if err := p.expect(token.TokMap.Type("id")); err != nil {
186 | return err
187 | }
188 |
189 | if err := p.expect(token.TokMap.Type("openParan")); err != nil {
190 | return err
191 | }
192 |
193 | p.CodeGenerator.MemoryManager.PushNewFunctionSegment(true, 0, 0)
194 |
195 | params, err := p.parseParameterList()
196 | if err != nil {
197 | return err
198 | }
199 |
200 | if err := p.SymbolTable.AddFunction(string(functionId), params, p.curr.Line, p.curr.Column); err != nil {
201 | return err
202 | }
203 |
204 | if err := p.SymbolTable.EnterFunctionScope(string(functionId)); err != nil {
205 | return err
206 | }
207 |
208 | if err := p.expect(token.TokMap.Type("closeParan")); err != nil {
209 | return err
210 | }
211 |
212 | functionStartQuad := len(p.CodeGenerator.Quads)
213 | if err := p.SymbolTable.UpdateFunctionStartQuad(string(functionId), functionStartQuad); err != nil {
214 | return err
215 | }
216 |
217 | if err := p.parseFunctionBlock(); err != nil {
218 | return err
219 | }
220 |
221 | if err := p.CodeGenerator.HandleENDPROC(); err != nil {
222 | return err
223 | }
224 |
225 | if err := p.CodeGenerator.MemoryManager.PopFunctionSegment(); err != nil {
226 | return err
227 | }
228 |
229 | if err := p.expect(token.TokMap.Type("terminator")); err != nil {
230 | return err
231 | }
232 |
233 | p.SymbolTable.ExitFunctionScope()
234 | return p.parseFunctionList()
235 | }
236 |
237 | func (p *Parser) parseParameterList() ([]shared.Variable, error) {
238 | if p.curr.Type == token.TokMap.Type("closeParan") {
239 | return []shared.Variable{}, nil
240 | }
241 |
242 | currentParams := make([]shared.Variable, 0)
243 | currId := p.curr
244 | currType, err := p.parseParameter()
245 | if err != nil {
246 | return []shared.Variable{}, err
247 | }
248 |
249 | semType, err := p.returnSemanticType(currType)
250 | addr, err := p.CodeGenerator.MemoryManager.AllocateLocal(semType)
251 |
252 | if err != nil {
253 | return []shared.Variable{}, err
254 | }
255 |
256 | currentParams = append(currentParams, shared.Variable{
257 | Name: string(currId.Lit),
258 | Type: semType,
259 | Line: currId.Line,
260 | Column: currId.Column,
261 | Address: addr,
262 | })
263 |
264 | if err != nil {
265 | return []shared.Variable{}, err
266 | }
267 |
268 | for p.curr.Type == token.TokMap.Type("repeatTerminator") {
269 | p.next() // consume the repeat terminator
270 | currId := p.curr
271 | currType, err := p.parseParameter()
272 | semType, err := p.returnSemanticType(currType)
273 |
274 | if err != nil {
275 | return []shared.Variable{}, err
276 | }
277 | addr, err := p.CodeGenerator.MemoryManager.AllocateLocal(semType)
278 | if err != nil {
279 | return []shared.Variable{}, err
280 | }
281 | currentParams = append(currentParams, shared.Variable{
282 | Name: string(currId.Lit),
283 | Type: semType,
284 | Line: currId.Line,
285 | Column: currId.Column,
286 | Address: addr,
287 | })
288 |
289 | if err != nil {
290 | return []shared.Variable{}, err
291 | }
292 | }
293 |
294 | return currentParams, nil
295 | }
296 |
297 | func (p *Parser) parseParameter() (string, error) {
298 | if err := p.expect(token.TokMap.Type("id")); err != nil {
299 | return "", err
300 | }
301 |
302 | if err := p.expect(token.TokMap.Type("typeAssignOp")); err != nil {
303 | return "", err
304 | }
305 |
306 | currType, err := p.parseType()
307 | if err != nil {
308 | return "", err
309 | }
310 |
311 | return currType, nil
312 | }
313 |
314 | func (p *Parser) parseBlock() error {
315 | if err := p.expect(token.TokMap.Type("openBrace")); err != nil {
316 | return err
317 | }
318 |
319 | if err := p.parseStatementList(); err != nil {
320 | return err
321 | }
322 |
323 | return p.expect(token.TokMap.Type("closeBrace"))
324 | }
325 |
326 | func (p *Parser) parseFunctionBlock() error {
327 | if err := p.expect(token.TokMap.Type("openBrace")); err != nil {
328 | return err
329 | }
330 |
331 | if err := p.parseVarDeclarationSection(true); err != nil {
332 | return err
333 | }
334 |
335 | if err := p.parseStatementList(); err != nil {
336 | return err
337 | }
338 |
339 | return p.expect(token.TokMap.Type("closeBrace"))
340 | }
341 |
342 | // Parsing Statements
343 | func (p *Parser) parseStatementList() error {
344 | for {
345 | validStatementStart, err := p.isStatementStart()
346 | if err != nil {
347 | return err
348 | }
349 |
350 | if !validStatementStart {
351 | break // No more statements to parse
352 | }
353 |
354 | if err := p.parseStatement(); err != nil {
355 | return err
356 | }
357 | }
358 | return nil
359 | }
360 |
361 | func (p *Parser) parseStatement() error {
362 | validStatementStart, err := p.isStatementStart()
363 |
364 | if !validStatementStart {
365 | return nil
366 | }
367 |
368 | if err != nil {
369 | return err
370 | }
371 |
372 | switch p.curr.Type {
373 | case token.TokMap.Type("kwdIf"):
374 | return p.parseIfStatement()
375 | case token.TokMap.Type("kwdWhile"):
376 | return p.parseWhileStatement()
377 | case token.TokMap.Type("kwdPrint"):
378 | return p.parsePrintStatement()
379 | case token.TokMap.Type("id"):
380 | // Functionality of function calls to be added
381 |
382 | idToken := p.curr
383 | p.next()
384 | nextToken := p.curr
385 | if nextToken.Type == token.TokMap.Type("openParan") {
386 | return p.parseFunctionCall(idToken)
387 | } else if nextToken.Type == token.TokMap.Type("assignOp") {
388 | if err := p.SymbolTable.ValidateVarAssignment(string(idToken.Lit), idToken.Line); err != nil {
389 | return err
390 | }
391 | return p.parseAssignment(idToken, nextToken)
392 | } else {
393 | return fmt.Errorf("expected either = or (, got %v at line %d, column %d", token.TokMap.Id(nextToken.Type), nextToken.Line, nextToken.Column)
394 | }
395 | }
396 | return nil
397 | }
398 |
399 | func (p *Parser) parseAssignment(id, nextToken *token.Token) error {
400 | if nextToken.Type != token.TokMap.Type("assignOp") {
401 | return fmt.Errorf("expected =, got %v at line %d, column %d", nextToken.Type, nextToken.Line, nextToken.Column)
402 | }
403 | p.next()
404 |
405 | _, err := p.parseExpression()
406 | currType, err := p.SymbolTable.GetType(string(id.Lit))
407 | if err != nil {
408 | return err
409 | }
410 |
411 | targetAddr, err := p.SymbolTable.GetVariableAddress(string(id.Lit))
412 | if err != nil {
413 | return err
414 | }
415 |
416 | // fmt.Println("The expression type is ", exprType, "and the tok", string(id.Lit))
417 | if err := p.CodeGenerator.HandleAssignment(targetAddr, currType); err != nil {
418 | return err
419 | }
420 | if err := p.expect(token.TokMap.Type("terminator")); err != nil {
421 | return err
422 | }
423 |
424 | return nil
425 | }
426 |
427 | func (p *Parser) parseWhileStatement() error {
428 | if err := p.expect(token.TokMap.Type("kwdWhile")); err != nil {
429 | return err
430 | }
431 |
432 | startIndex := p.CodeGenerator.HandleWhileStart()
433 |
434 | if err := p.expect(token.TokMap.Type("openParan")); err != nil {
435 | return err
436 | }
437 |
438 | _, err := p.parseExpression()
439 | if err != nil {
440 | return err
441 | }
442 |
443 | // QUADS
444 | if err := p.CodeGenerator.HandleWhileCondition(); err != nil {
445 | return err
446 | }
447 |
448 | if err := p.expect(token.TokMap.Type("closeParan")); err != nil {
449 | return err
450 | }
451 |
452 | if err := p.parseBlock(); err != nil {
453 | return err
454 | }
455 |
456 | if err := p.CodeGenerator.HandleWhileEnd(startIndex); err != nil {
457 | return err
458 | }
459 |
460 | return nil
461 | }
462 |
463 | func (p *Parser) parseIfStatement() error {
464 | if err := p.expect(token.TokMap.Type("kwdIf")); err != nil {
465 | return err
466 | }
467 |
468 | if err := p.expect(token.TokMap.Type("openParan")); err != nil {
469 | return err
470 | }
471 |
472 | _, err := p.parseExpression()
473 | if err != nil {
474 | return err
475 | }
476 |
477 | if err := p.expect(token.TokMap.Type("closeParan")); err != nil {
478 | return err
479 | }
480 |
481 | // QUADS
482 | if err := p.CodeGenerator.HandleIfStatement(); err != nil {
483 | return err
484 | }
485 |
486 | if err := p.parseBlock(); err != nil {
487 | return err
488 | }
489 |
490 | if p.curr.Type == token.TokMap.Type("kwdElse") {
491 | p.next()
492 | if err := p.CodeGenerator.HandleElse(); err != nil {
493 | return err
494 | }
495 |
496 | if err := p.parseBlock(); err != nil {
497 | return err
498 | }
499 |
500 | if err := p.CodeGenerator.HandleEndIf(); err != nil {
501 | return err
502 | }
503 |
504 | return nil
505 | }
506 |
507 | if err := p.CodeGenerator.HandleEndIf(); err != nil {
508 | return err
509 | }
510 |
511 | return nil
512 | }
513 |
514 | func (p *Parser) parsePrintStatement() error {
515 | if err := p.expect(token.TokMap.Type("kwdPrint")); err != nil {
516 | return err
517 | }
518 |
519 | if err := p.expect(token.TokMap.Type("openParan")); err != nil {
520 | return err
521 | }
522 |
523 | if err := p.parsePrintList(); err != nil {
524 | return err
525 | }
526 |
527 | return p.expect(token.TokMap.Type("closeParan"))
528 | }
529 |
530 | func (p *Parser) parseFunctionCall(id *token.Token) error {
531 | functionName := string(id.Lit)
532 |
533 | if err := p.expect(token.TokMap.Type("openParan")); err != nil {
534 | return err
535 | }
536 | if err := p.CodeGenerator.HandleERA(functionName); err != nil {
537 | return err
538 | }
539 |
540 | arguments, err := p.parseArgumentList()
541 | if err != nil {
542 | return err
543 | }
544 |
545 | if err := p.expect(token.TokMap.Type("closeParan")); err != nil {
546 | return err
547 | }
548 |
549 | if err := p.SymbolTable.ValidateFunctionCall(string(id.Lit), id.Line, arguments); err != nil {
550 | return err
551 | }
552 |
553 | startQuad, err := p.SymbolTable.GetFunctionStartQuad(string(id.Lit))
554 |
555 | if err != nil {
556 | return err
557 | }
558 |
559 | if err := p.CodeGenerator.HandleGOSUB(string(id.Lit), startQuad); err != nil {
560 | return err
561 | }
562 |
563 | return nil
564 | }
565 |
566 | func (p *Parser) parseArgumentList() ([]shared.Type, error) {
567 | if p.curr.Type == token.TokMap.Type("closeParan") {
568 | return []shared.Type{}, nil
569 | }
570 | paramCount := 0
571 | argumentTypes := make([]shared.Type, 0)
572 | currType, err := p.parseExpression()
573 | if err != nil {
574 | return []shared.Type{}, err
575 | }
576 |
577 | if !p.CodeGenerator.OperandStack.IsEmpty() {
578 | arg := p.CodeGenerator.OperandStack.Pop()
579 | p.CodeGenerator.TypeStack.Pop()
580 | if err := p.CodeGenerator.HandleParam(arg, paramCount); err != nil {
581 | return []shared.Type{}, err
582 | }
583 | paramCount++
584 | }
585 |
586 | argumentTypes = append(argumentTypes, currType)
587 |
588 | for p.curr.Type == token.TokMap.Type("repeatTerminator") {
589 | p.next()
590 | argType, err := p.parseExpression()
591 | argumentTypes = append(argumentTypes, argType)
592 | if err != nil {
593 | return []shared.Type{}, err
594 | }
595 |
596 | if !p.CodeGenerator.OperandStack.IsEmpty() {
597 | arg := p.CodeGenerator.OperandStack.Pop()
598 | p.CodeGenerator.TypeStack.Pop()
599 | if err := p.CodeGenerator.HandleParam(arg, paramCount); err != nil {
600 | return []shared.Type{}, err
601 | }
602 | paramCount++
603 | }
604 |
605 | //argumentTypes = append(argumentTypes, argType)
606 | }
607 | return argumentTypes, nil
608 | }
609 |
610 | func (p *Parser) parsePrintList() error {
611 | printItems := make([]interface{}, 0)
612 | item, err := p.parsePrintItem()
613 | if err != nil {
614 | return err
615 | }
616 |
617 | printItems = append(printItems, item)
618 |
619 | for p.curr.Type == token.TokMap.Type("repeatTerminator") {
620 | p.next()
621 | item, err := p.parsePrintItem()
622 | if err != nil {
623 | return err
624 | }
625 | printItems = append(printItems, item)
626 | }
627 |
628 | if err := p.CodeGenerator.HandlePrint(printItems); err != nil {
629 | return err
630 | }
631 | return nil
632 | }
633 |
634 | func (p *Parser) parsePrintItem() (interface{}, error) {
635 |
636 | if p.curr.Type == token.TokMap.Type("stringLit") {
637 | stringToSend := string(p.curr.Lit)
638 | p.next()
639 | return stringToSend, nil
640 | }
641 |
642 | _, err := p.parseExpression()
643 | if err != nil {
644 | return nil, err
645 | }
646 |
647 | if p.CodeGenerator.OperandStack.IsEmpty() {
648 | return nil, fmt.Errorf("missing expression result for print statement")
649 | }
650 | result := p.CodeGenerator.OperandStack.Pop()
651 | p.CodeGenerator.TypeStack.Pop()
652 |
653 | //if err := p.CodeGenerator.HandlePrint(result); err != nil {
654 | // return err
655 | //}
656 | //
657 | //if err != nil {
658 | // return err
659 | //}
660 |
661 | return result, nil
662 | }
663 |
664 | func (p *Parser) parseExpression() (shared.Type, error) {
665 | leftType, err := p.parseExp()
666 | if err != nil {
667 | return shared.TypeError, err
668 | }
669 |
670 | for p.curr.Type == token.TokMap.Type("relOp") {
671 | operator := string(p.curr.Lit)
672 | p.CodeGenerator.OperatorStack.Push(operator)
673 | p.next()
674 |
675 | _, err := p.parseExp()
676 | if err != nil {
677 | return shared.TypeError, err
678 | }
679 |
680 | if err := p.CodeGenerator.HandleOp(); err != nil {
681 | return shared.TypeError, err
682 | }
683 | }
684 |
685 | return leftType, nil
686 | }
687 |
688 | func (p *Parser) parseExp() (shared.Type, error) {
689 | leftType, err := p.parseTerm()
690 | if err != nil {
691 | return shared.TypeError, err
692 | }
693 |
694 | for p.curr.Type == token.TokMap.Type("expressionOp") {
695 | operator := string(p.curr.Lit)
696 | p.next()
697 |
698 | p.CodeGenerator.OperatorStack.Push(operator)
699 |
700 | rightType, err := p.parseTerm()
701 | if err != nil {
702 | return shared.TypeError, err
703 | }
704 |
705 | if err := p.CodeGenerator.HandleOp(); err != nil {
706 | return shared.TypeError, err
707 | }
708 |
709 | if leftType == shared.TypeFloat || rightType == shared.TypeFloat {
710 | leftType = shared.TypeFloat
711 | } else {
712 | leftType = shared.TypeInt
713 | }
714 |
715 | }
716 |
717 | return leftType, nil
718 | }
719 |
720 | func (p *Parser) parseTerm() (shared.Type, error) {
721 | leftType, err := p.parseFactor()
722 | if err != nil {
723 | return shared.TypeError, err
724 | }
725 |
726 | if p.curr.Type == token.TokMap.Type("termOp") {
727 | operator := string(p.curr.Lit)
728 | p.next()
729 |
730 | p.CodeGenerator.OperatorStack.Push(operator)
731 |
732 | rightType, err := p.parseTerm()
733 |
734 | if err := p.CodeGenerator.HandleOp(); err != nil {
735 | return shared.TypeError, err
736 | }
737 |
738 | if err != nil {
739 | return shared.TypeError, err
740 | }
741 |
742 | // Check compatibility using semantic cube
743 | if leftType == shared.TypeFloat || rightType == shared.TypeFloat {
744 | return shared.TypeFloat, nil
745 | }
746 |
747 | return shared.TypeInt, nil
748 | }
749 |
750 | return leftType, nil
751 | }
752 |
753 | func (p *Parser) parseFactor() (shared.Type, error) {
754 | switch p.curr.Type {
755 | case token.TokMap.Type("openParan"):
756 | p.CodeGenerator.HandleOpenParen()
757 | p.next()
758 | exprType, err := p.parseExpression()
759 | if err != nil {
760 | return shared.TypeError, err
761 | }
762 |
763 | if p.curr.Type == token.TokMap.Type("closeParan") {
764 | if err := p.CodeGenerator.HandleCloseParen(); err != nil {
765 | return exprType, err
766 | }
767 | }
768 | if err := p.expect(token.TokMap.Type("closeParan")); err != nil {
769 | return shared.TypeError, err
770 | }
771 | return exprType, nil
772 | case token.TokMap.Type("expressionOp"):
773 | isNegative := string(p.curr.Lit) == "-"
774 | p.next()
775 |
776 | switch p.curr.Type {
777 | // Logic for negatives??? Plus sign should be parsed but ignored.
778 | // Pending logic for negative ids
779 | case token.TokMap.Type("intLit"), token.TokMap.Type("floatLit"):
780 | tok := p.curr
781 | tokType, err := p.getType(p.curr)
782 | if err != nil {
783 | return shared.TypeError, err
784 | }
785 |
786 | value := string(tok.Lit)
787 | if isNegative {
788 | value = "-" + value
789 | }
790 |
791 | if err := p.CodeGenerator.HandleFactor(value, tokType, p.SymbolTable); err != nil {
792 | return shared.TypeError, err
793 | }
794 |
795 | return tokType, nil
796 | case token.TokMap.Type("id"):
797 | tok := p.curr
798 | tokType, err := p.getType(p.curr)
799 | if err != nil {
800 | return shared.TypeError, err
801 | }
802 | if err := p.CodeGenerator.HandleFactor(string(tok.Lit), tokType, p.SymbolTable); err != nil {
803 | return shared.TypeError, err
804 | }
805 |
806 | if isNegative {
807 | if err := p.CodeGenerator.HandleNegation(); err != nil {
808 | return shared.TypeError, err
809 | }
810 | }
811 |
812 | return tokType, nil
813 | default:
814 | return shared.TypeError, fmt.Errorf("expected number after %s", p.curr.Lit)
815 | }
816 | case token.TokMap.Type("id"), token.TokMap.Type("intLit"), token.TokMap.Type("floatLit"):
817 | tok := p.curr
818 | tokType, err := p.getType(tok)
819 | // fmt.Printf("In Parser parseFactor: token=%v type=%v lit=%v\n", p.curr.Type, tokType, string(tok.Lit))
820 | if err != nil {
821 | return shared.TypeError, err
822 | }
823 | if err := p.CodeGenerator.HandleFactor(string(tok.Lit), tokType, p.SymbolTable); err != nil {
824 | return shared.TypeError, err
825 | }
826 | return tokType, nil
827 | default:
828 | return shared.TypeError, fmt.Errorf("unexpected token in factor: %v in line %v and %v",
829 | token.TokMap.Id(p.curr.Type), p.curr.Line, string(p.curr.Lit))
830 | }
831 | }
832 |
833 | func (p *Parser) parseMainSection() error {
834 | if err := p.expect(token.TokMap.Type("kwdBegin")); err != nil {
835 | return err
836 | }
837 |
838 | mainQuadIndex := len(p.CodeGenerator.Quads)
839 | p.CodeGenerator.Quads[0].Result = mainQuadIndex
840 |
841 | if err := p.parseStatementList(); err != nil {
842 | return err
843 | }
844 |
845 | if err := p.expect(token.TokMap.Type("kwdEnd")); err != nil {
846 | return err
847 | }
848 |
849 | return nil
850 | }
851 |
--------------------------------------------------------------------------------
/src/parser/util.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "fmt"
5 | "pogo/src/shared"
6 | "pogo/src/token"
7 | )
8 |
9 | func (p *Parser) next() {
10 | p.curr = p.lexer.Scan()
11 | }
12 |
13 | func (p *Parser) expect(typ token.Type) error {
14 | //fmt.Println("Processing token", string(p.curr.Lit), "as ", token.TokMap.Id(typ))
15 | // fmt.Println("This is the context", p.lexer.s)
16 | if p.curr.Type != typ {
17 | return p.error(fmt.Sprintf("expected %v, got %v", token.TokMap.Id(typ), token.TokMap.Id(p.curr.Type)))
18 | }
19 | p.next()
20 | return nil
21 | }
22 |
23 | // Error helper function
24 | func (p *Parser) error(msg string) error {
25 | return fmt.Errorf("line %d: %s", p.curr.Line, msg)
26 | }
27 |
28 | func (p *Parser) isStatementStart() (bool, error) {
29 | statementStarts := map[token.Type]struct{}{
30 | token.TokMap.Type("kwdWhile"): {},
31 | token.TokMap.Type("kwdIf"): {},
32 | token.TokMap.Type("kwdPrint"): {},
33 | token.TokMap.Type("id"): {},
34 | }
35 |
36 | if _, exists := statementStarts[p.curr.Type]; exists {
37 | return true, nil
38 | }
39 | return false, nil
40 | }
41 |
42 | func (p *Parser) addVariablesToSymbolTable(semType shared.Type, currentVars []string) error {
43 |
44 | for _, varName := range currentVars {
45 |
46 | var addr int
47 | var err error
48 |
49 | if p.SymbolTable.GetScope() == "global" {
50 | addr, err = p.CodeGenerator.MemoryManager.AllocateGlobal(semType)
51 | } else {
52 | addr, err = p.CodeGenerator.MemoryManager.AllocateLocal(semType)
53 | if err != nil {
54 | return err
55 | }
56 | if err := p.SymbolTable.IncrementFunctionVarCount(semType); err != nil {
57 | return err
58 | }
59 | }
60 |
61 | if err != nil {
62 | return err
63 | }
64 |
65 | if err := p.SymbolTable.AddVariable(varName, semType, p.curr.Line, p.curr.Column, addr); err != nil {
66 | return err
67 | }
68 | }
69 |
70 | return nil
71 | }
72 |
73 | func (p *Parser) returnSemanticType(currType string) (shared.Type, error) {
74 | var semType shared.Type
75 | switch string(currType) {
76 | case "int":
77 | semType = shared.TypeInt
78 | case "float":
79 | semType = shared.TypeFloat
80 | default:
81 | return shared.TypeError, fmt.Errorf("line %d: unsupported type: %s", p.curr.Line, string(currType))
82 | }
83 | return semType, nil
84 | }
85 |
86 | func (p *Parser) getType(tok *token.Token) (shared.Type, error) {
87 | switch tok.Type {
88 | case token.TokMap.Type("intLit"):
89 | p.next()
90 | return shared.TypeInt, nil
91 | case token.TokMap.Type("floatLit"):
92 | p.next()
93 | return shared.TypeFloat, nil
94 | case token.TokMap.Type("id"):
95 | p.next()
96 | return p.SymbolTable.GetType(string(tok.Lit))
97 | default:
98 | return shared.TypeError, fmt.Errorf("expected number after %s", p.curr.Lit)
99 | }
100 | }
101 |
102 | func (p *Parser) isAssignable(varType, exprType shared.Type) bool {
103 | if varType == exprType {
104 | return true
105 | }
106 | // Allow int -> float conversion
107 | if varType == shared.TypeFloat && exprType == shared.TypeInt {
108 | return true
109 | }
110 | return false
111 | }
112 |
--------------------------------------------------------------------------------
/src/semantic/CodeGenerator.go:
--------------------------------------------------------------------------------
1 | package semantic
2 |
3 | import (
4 | "fmt"
5 | "pogo/src/shared"
6 | "pogo/src/virtualmachine"
7 | )
8 |
9 | // Quadruple struct
10 |
11 | type QuadrupleList struct {
12 | Quads []shared.Quadruple
13 | OperatorStack *shared.Stack
14 | OperandStack *shared.Stack
15 | TypeStack *shared.Stack
16 | JumpStack *shared.Stack
17 | TempCounter int
18 | SemanticCube *SemanticCube
19 | MemoryManager *virtualmachine.MemoryManager
20 | }
21 |
22 | func NewQuadrupleList() *QuadrupleList {
23 | return &QuadrupleList{
24 | Quads: make([]shared.Quadruple, 0),
25 | OperatorStack: shared.NewStack(),
26 | OperandStack: shared.NewStack(),
27 | TypeStack: shared.NewStack(),
28 | JumpStack: shared.NewStack(),
29 | TempCounter: 0,
30 | SemanticCube: NewSemanticCube(),
31 | MemoryManager: virtualmachine.NewMemoryManager(),
32 | }
33 |
34 | }
35 |
36 | func (ql *QuadrupleList) HandleProgramStart() {
37 | quad := shared.Quadruple{
38 | Operator: "goto",
39 | LeftOp: nil,
40 | RightOp: nil,
41 | Result: nil,
42 | }
43 |
44 | ql.Quads = append(ql.Quads, quad)
45 | }
46 |
47 | func (ql *QuadrupleList) NewTemp(tempType shared.Type) (int, error) {
48 | addr, err := ql.MemoryManager.AllocateTemp(tempType)
49 | if err != nil {
50 | return -1, err
51 | }
52 | return addr, nil
53 | }
54 |
55 | func (ql *QuadrupleList) HandleOpenParen() {
56 | ql.OperatorStack.Push("(")
57 | }
58 |
59 | func (ql *QuadrupleList) HandleCloseParen() error {
60 | for !ql.OperatorStack.IsEmpty() {
61 | topOp := ql.OperatorStack.Top()
62 | if topOp == nil {
63 | return fmt.Errorf("mismatched parentheses: no opening parenthesis found")
64 | }
65 |
66 | if topOp.(string) == "(" {
67 | ql.OperatorStack.Pop()
68 | return nil
69 | }
70 |
71 | operator := ql.OperatorStack.Pop().(string)
72 |
73 | if ql.OperandStack.Size() < 2 {
74 | return fmt.Errorf("insufficient operands for operator %s", operator)
75 | }
76 |
77 | rightOp := ql.OperandStack.Pop()
78 | rightType := ql.TypeStack.Pop().(shared.Type)
79 | leftOp := ql.OperandStack.Pop()
80 | leftType := ql.TypeStack.Pop().(shared.Type)
81 |
82 | resultType := ql.SemanticCube.GetResultType(leftType, rightType, operator)
83 | if resultType == shared.TypeError {
84 | return fmt.Errorf("type mismatch for operation %v %s %v", leftType, operator, rightType)
85 | }
86 |
87 | result, err := ql.NewTemp(resultType)
88 |
89 | if err != nil {
90 | return err
91 | }
92 |
93 | quad := shared.Quadruple{
94 | Operator: operator,
95 | LeftOp: leftOp,
96 | RightOp: rightOp,
97 | Result: result,
98 | }
99 | ql.Quads = append(ql.Quads, quad)
100 |
101 | ql.OperandStack.Push(result)
102 | ql.TypeStack.Push(resultType)
103 | }
104 |
105 | return fmt.Errorf("mismatched parentheses: no opening parenthesis found")
106 | }
107 |
108 | func (ql *QuadrupleList) HandleOp() error {
109 | if ql.OperatorStack.Top() != nil {
110 | right := ql.OperandStack.Pop()
111 | rightType := ql.TypeStack.Pop().(shared.Type)
112 | left := ql.OperandStack.Pop()
113 | leftType := ql.TypeStack.Pop().(shared.Type)
114 | op := ql.OperatorStack.Pop().(string)
115 |
116 | resultType := ql.SemanticCube.GetResultType(leftType, rightType, op)
117 | if resultType == shared.TypeError {
118 | return fmt.Errorf("type mismatch for operation %v %s %v", leftType, op, rightType)
119 | }
120 |
121 | result, err := ql.MemoryManager.AllocateTemp(resultType)
122 |
123 | if err != nil {
124 | return err
125 | }
126 | ql.TempCounter++
127 |
128 | ql.Quads = append(ql.Quads, shared.Quadruple{
129 | Operator: op,
130 | LeftOp: left,
131 | RightOp: right,
132 | Result: result,
133 | })
134 |
135 | ql.OperandStack.Push(result)
136 | ql.TypeStack.Push(resultType)
137 | }
138 |
139 | return nil
140 | }
141 |
142 | func (ql *QuadrupleList) HandleFactor(value string, valueType shared.Type, SymbolTable *SymbolTable) error {
143 | var addr int
144 | var err error
145 |
146 | if isNumeric(value) {
147 | addr, err = ql.MemoryManager.AllocateConstant(value)
148 | // fmt.Println("Numeric", addr, err)
149 | } else {
150 | addr, err = SymbolTable.GetVariableAddress(value)
151 | }
152 |
153 | if err != nil {
154 | return fmt.Errorf("error allocating value: %v", err, value)
155 | }
156 |
157 | ql.OperandStack.Push(addr)
158 | ql.TypeStack.Push(valueType)
159 | //fmt.Printf("After HandleFactor(%v): Operands=%v, Operators=%v\n",
160 | // value,
161 | // ql.OperandStack,
162 | // ql.OperatorStack)
163 | return nil
164 | }
165 |
166 | func (ql *QuadrupleList) HandleNegation() error {
167 | value := ql.OperandStack.Pop()
168 | valueType := ql.TypeStack.Pop().(shared.Type)
169 |
170 | minusOne, err := ql.MemoryManager.AllocateConstant("-1")
171 | if err != nil {
172 | return fmt.Errorf("failed to allocate -1 constant: %v", err)
173 | }
174 |
175 | result, err := ql.NewTemp(valueType)
176 | if err != nil {
177 | return fmt.Errorf("failed to allocate temporary for negation: %v", err)
178 | }
179 |
180 | quad := shared.Quadruple{
181 | Operator: "*",
182 | LeftOp: value,
183 | RightOp: minusOne,
184 | Result: result,
185 | }
186 |
187 | ql.Quads = append(ql.Quads, quad)
188 |
189 | ql.OperandStack.Push(result)
190 | ql.TypeStack.Push(valueType)
191 |
192 | return nil
193 | }
194 |
195 | func (ql *QuadrupleList) HandleAssignment(target int, targetType shared.Type) error {
196 | if ql.OperandStack.Top() == nil {
197 | return fmt.Errorf("missing expression for assignment")
198 | }
199 |
200 | value := ql.OperandStack.Pop()
201 | valueType := ql.TypeStack.Pop().(shared.Type)
202 |
203 | // Check if assignment is valid using semantic cube
204 | resultType := ql.SemanticCube.GetResultType(targetType, valueType, "=")
205 | if resultType == shared.TypeError {
206 | return fmt.Errorf("cannot assign value of type %v to variable of type %v", valueType, targetType)
207 | }
208 |
209 | ql.Quads = append(ql.Quads, shared.Quadruple{
210 | Operator: "=",
211 | LeftOp: value,
212 | RightOp: nil,
213 | Result: target,
214 | })
215 |
216 | return nil
217 | }
218 |
219 | func (ql *QuadrupleList) HandleWhileStart() int {
220 | return len(ql.Quads)
221 | }
222 |
223 | func (ql *QuadrupleList) HandleWhileCondition() error {
224 | if ql.OperandStack.IsEmpty() {
225 | return fmt.Errorf("missing condition for while statement")
226 | }
227 |
228 | condition := ql.OperandStack.Pop()
229 | condType := ql.TypeStack.Pop()
230 |
231 | if condType != shared.TypeInt {
232 | return fmt.Errorf("condition must be boolean (result of comparison)")
233 | }
234 |
235 | quad := shared.Quadruple{
236 | Operator: "gotof",
237 | LeftOp: condition,
238 | RightOp: nil,
239 | Result: nil,
240 | }
241 |
242 | jumpIndex := len(ql.Quads)
243 | ql.Quads = append(ql.Quads, quad)
244 |
245 | ql.JumpStack.Push(jumpIndex)
246 |
247 | return nil
248 | }
249 |
250 | func (ql *QuadrupleList) HandleWhileEnd(startIndex int) error {
251 | if ql.JumpStack.IsEmpty() {
252 | return fmt.Errorf("mismatched while: no pending jumps found")
253 | }
254 |
255 | ql.Quads = append(ql.Quads, shared.Quadruple{
256 | Operator: "goto",
257 | LeftOp: nil,
258 | RightOp: nil,
259 | Result: startIndex,
260 | })
261 |
262 | falseJumpIndex := ql.JumpStack.Pop().(int)
263 | ql.Quads[falseJumpIndex].Result = len(ql.Quads)
264 |
265 | return nil
266 | }
267 |
268 | func (ql *QuadrupleList) HandleIfStatement() error {
269 | if ql.OperandStack.IsEmpty() {
270 | return fmt.Errorf("missing condition for if statement")
271 | }
272 |
273 | condition := ql.OperandStack.Pop()
274 | condType := ql.TypeStack.Pop()
275 |
276 | if condType != shared.TypeInt {
277 | return fmt.Errorf("condition must be 0 or 1 (result of comparison)")
278 | }
279 |
280 | quad := shared.Quadruple{
281 | Operator: "gotof",
282 | LeftOp: condition,
283 | RightOp: nil,
284 | Result: nil,
285 | }
286 |
287 | jumpIndex := len(ql.Quads)
288 | ql.Quads = append(ql.Quads, quad)
289 |
290 | ql.JumpStack.Push(jumpIndex)
291 |
292 | return nil
293 | }
294 |
295 | func (ql *QuadrupleList) HandleElse() error {
296 |
297 | quad := shared.Quadruple{
298 | Operator: "goto",
299 | LeftOp: nil,
300 | RightOp: nil,
301 | Result: nil,
302 | }
303 |
304 | gotoIndex := len(ql.Quads)
305 | ql.Quads = append(ql.Quads, quad)
306 |
307 | if ql.JumpStack.IsEmpty() {
308 | return fmt.Errorf("mismatched if-else: no corresponding if statement found")
309 | }
310 | falseJumpIndex := ql.JumpStack.Pop().(int)
311 |
312 | ql.Quads[falseJumpIndex].Result = len(ql.Quads)
313 |
314 | ql.JumpStack.Push(gotoIndex)
315 |
316 | return nil
317 | }
318 |
319 | func (ql *QuadrupleList) HandleEndIf() error {
320 | if ql.JumpStack.IsEmpty() {
321 | return fmt.Errorf("mismatched if-else: no pending jumps found")
322 | }
323 |
324 | jumpIndex := ql.JumpStack.Pop().(int)
325 |
326 | ql.Quads[jumpIndex].Result = len(ql.Quads)
327 |
328 | return nil
329 | }
330 |
331 | func (ql *QuadrupleList) HandlePrint(items []interface{}) error {
332 | addresses := make([]int, len(items))
333 |
334 | for i, item := range items {
335 | switch v := item.(type) {
336 | case string:
337 | addr, err := ql.MemoryManager.AllocateStringAddress(v)
338 | if err != nil {
339 | return fmt.Errorf("error allocating string: %v", err)
340 | }
341 | addresses[i] = addr
342 | case int:
343 | addresses[i] = v
344 | default:
345 | return fmt.Errorf("unsupported print item type: %T", item)
346 | }
347 | }
348 |
349 | quad := shared.Quadruple{
350 | Operator: "print",
351 | LeftOp: addresses,
352 | RightOp: nil,
353 | Result: nil,
354 | }
355 |
356 | ql.Quads = append(ql.Quads, quad)
357 | return nil
358 | }
359 |
360 | func (ql *QuadrupleList) Print() {
361 | // fmt.Println("Generated Quadruples:")
362 | for i, quad := range ql.Quads {
363 | fmt.Printf("%d: (%v, %v, %v, %v)\n", i, quad.Operator, quad.LeftOp, quad.RightOp, quad.Result)
364 | }
365 | }
366 |
367 | func (ql *QuadrupleList) HandleERA(functionName string) error {
368 | quad := shared.Quadruple{
369 | Operator: "era",
370 | LeftOp: functionName,
371 | RightOp: nil,
372 | Result: nil,
373 | }
374 | ql.Quads = append(ql.Quads, quad)
375 | return nil
376 | }
377 |
378 | func (ql *QuadrupleList) HandleParam(value interface{}, paramNum int) error {
379 | quad := shared.Quadruple{
380 | Operator: "param",
381 | LeftOp: value,
382 | RightOp: paramNum,
383 | Result: nil,
384 | }
385 | ql.Quads = append(ql.Quads, quad)
386 | return nil
387 | }
388 |
389 | func (ql *QuadrupleList) HandleGOSUB(functionName string, startQuad int) error {
390 | quad := shared.Quadruple{
391 | Operator: "gosub",
392 | LeftOp: functionName,
393 | RightOp: len(ql.Quads) + 1,
394 | Result: startQuad,
395 | }
396 | ql.Quads = append(ql.Quads, quad)
397 | return nil
398 | }
399 |
400 | func (ql *QuadrupleList) HandleENDPROC() error {
401 | quad := shared.Quadruple{
402 | Operator: "endproc",
403 | LeftOp: nil,
404 | RightOp: nil,
405 | Result: nil,
406 | }
407 | ql.Quads = append(ql.Quads, quad)
408 | return nil
409 | }
410 |
411 | func (ql *QuadrupleList) PrintStacks() {
412 | fmt.Println("Stack Operators", ql.OperatorStack)
413 | fmt.Println("Stack Operands", ql.OperandStack)
414 | fmt.Println("Stack Types", ql.TypeStack)
415 | }
416 |
--------------------------------------------------------------------------------
/src/semantic/SemanticCube.go:
--------------------------------------------------------------------------------
1 | package semantic
2 |
3 | import "pogo/src/shared"
4 |
5 | type SemanticCube struct {
6 | cube map[shared.Type]map[shared.Type]map[string]shared.Type
7 | }
8 |
9 | func NewSemanticCube() *SemanticCube {
10 |
11 | cube := &SemanticCube{
12 | cube: make(map[shared.Type]map[shared.Type]map[string]shared.Type),
13 | }
14 | // Initialize semantic cube
15 | for _, t1 := range []shared.Type{shared.TypeInt, shared.TypeFloat} {
16 | cube.cube[t1] = make(map[shared.Type]map[string]shared.Type)
17 | for _, t2 := range []shared.Type{shared.TypeInt, shared.TypeFloat} {
18 | cube.cube[t1][t2] = make(map[string]shared.Type)
19 | }
20 | }
21 |
22 | arithOps := []string{"+", "-", "*", "/"}
23 | for _, op := range arithOps {
24 | // Int operations
25 | cube.cube[shared.TypeInt][shared.TypeInt][op] = shared.TypeInt
26 | //if op == "/" {
27 | // cube.cube[shared.TypeInt][shared.TypeInt][op] = shared.TypeFloat
28 | //}
29 | cube.cube[shared.TypeInt][shared.TypeFloat][op] = shared.TypeFloat
30 |
31 | cube.cube[shared.TypeFloat][shared.TypeInt][op] = shared.TypeFloat
32 | cube.cube[shared.TypeFloat][shared.TypeFloat][op] = shared.TypeFloat
33 | }
34 |
35 | relOps := []string{"<", ">", "==", "!=", "<=", ">="}
36 | for _, op := range relOps {
37 | cube.cube[shared.TypeInt][shared.TypeInt][op] = shared.TypeInt
38 | cube.cube[shared.TypeInt][shared.TypeFloat][op] = shared.TypeInt
39 | cube.cube[shared.TypeFloat][shared.TypeInt][op] = shared.TypeInt
40 | cube.cube[shared.TypeFloat][shared.TypeFloat][op] = shared.TypeInt
41 | }
42 |
43 | cube.cube[shared.TypeFloat][shared.TypeInt]["="] = shared.TypeFloat
44 | cube.cube[shared.TypeFloat][shared.TypeFloat]["="] = shared.TypeFloat
45 | cube.cube[shared.TypeInt][shared.TypeInt]["="] = shared.TypeInt
46 | cube.cube[shared.TypeInt][shared.TypeFloat]["="] = shared.TypeError
47 |
48 | return cube
49 | }
50 |
51 | func (sc *SemanticCube) GetResultType(t1, t2 shared.Type, operator string) shared.Type {
52 | if t1 == shared.TypeString || t2 == shared.TypeString {
53 | return shared.TypeError
54 | }
55 |
56 | if t1 == shared.TypeError || t2 == shared.TypeError {
57 | return shared.TypeError
58 | }
59 |
60 | if result, exists := sc.cube[t1][t2][operator]; exists {
61 | return result
62 | }
63 |
64 | return shared.TypeError
65 | }
66 |
67 | func (sc *SemanticCube) ValidatePrintItem(t shared.Type) bool {
68 | return t == shared.TypeInt || t == shared.TypeFloat || t == shared.TypeString
69 | }
70 |
--------------------------------------------------------------------------------
/src/semantic/SymbolTable.go:
--------------------------------------------------------------------------------
1 | package semantic
2 |
3 | import (
4 | "fmt"
5 | "pogo/src/shared"
6 | )
7 |
8 | type SymbolTable struct {
9 | variables map[string]map[string]interface{}
10 | scopeStack []string
11 | currentScope string
12 | }
13 |
14 | func NewSymbolTable() *SymbolTable {
15 | st := &SymbolTable{
16 | variables: make(map[string]map[string]interface{}),
17 | }
18 |
19 | st.variables["global"] = make(map[string]interface{})
20 | st.scopeStack = append(st.scopeStack, "global")
21 | st.currentScope = st.scopeStack[len(st.scopeStack)-1]
22 | return st
23 | }
24 |
25 | func (st *SymbolTable) GetType(name string) (shared.Type, error) {
26 | if st.variables[st.currentScope] == nil {
27 | st.variables[st.currentScope] = make(map[string]interface{})
28 | }
29 |
30 | if symbol, exists := st.variables[st.currentScope][name]; exists {
31 | switch v := symbol.(type) {
32 | case shared.Variable:
33 | return v.Type, nil
34 | default:
35 | return shared.TypeError, fmt.Errorf("symbol '%s' is not a variable", name)
36 | }
37 | }
38 |
39 | if st.currentScope != "global" {
40 | if symbol, exists := st.variables["global"][name]; exists {
41 | switch v := symbol.(type) {
42 | case shared.Variable:
43 | return v.Type, nil
44 | default:
45 | return shared.TypeError, fmt.Errorf("symbol '%s' is not a variable", name)
46 | }
47 | }
48 | }
49 |
50 | return shared.TypeError, fmt.Errorf("variable '%s' not declared in accessible scope", name)
51 | }
52 |
53 | func (st *SymbolTable) GetVariableAddress(name string) (int, error) {
54 | // fmt.Println("This is the current scope: ", st.currentScope)
55 |
56 | value, exists := st.variables[st.currentScope][name]
57 | if exists {
58 | if v, ok := value.(shared.Variable); ok {
59 | return v.Address, nil
60 | }
61 | }
62 |
63 | if st.currentScope != "global" {
64 | if value, exists := st.variables["global"][name]; exists {
65 | if v, ok := value.(shared.Variable); ok {
66 | return v.Address, nil
67 | }
68 | }
69 | }
70 |
71 | return -1, fmt.Errorf("error retrieving address for '%v", name)
72 | }
73 |
74 | func (st *SymbolTable) AddVariable(name string, varType shared.Type, line, column int, addr int) error {
75 | // Don't allow declaring string variables
76 | if st.variables[st.currentScope] == nil {
77 | st.variables[st.currentScope] = make(map[string]interface{})
78 | }
79 |
80 | if varType == shared.TypeString {
81 | return fmt.Errorf("line %d: cannot declare string variables, strings are only allowed in print statements", line)
82 | }
83 |
84 | if _, exists := st.variables[st.currentScope][name]; exists {
85 | return fmt.Errorf("line %d: symbol '%s' already declared in current scope", line, name)
86 | }
87 |
88 | st.variables[st.currentScope][name] = shared.Variable{
89 | Name: name,
90 | Type: varType,
91 | Line: line,
92 | Column: column,
93 | Address: addr,
94 | }
95 |
96 | return nil
97 | }
98 |
99 | func (st *SymbolTable) AddFunction(name string, params []shared.Variable, line, column int) error {
100 | if _, exists := st.variables["global"][name]; exists {
101 | return fmt.Errorf("line %d: symbol '%s' already declared", line, name)
102 | }
103 |
104 | st.variables[name] = make(map[string]interface{})
105 |
106 | // Add function to global scope
107 |
108 | intCount := 0
109 | floatCount := 0
110 |
111 | // Count parameters by type
112 | for _, param := range params {
113 | switch param.Type {
114 | case shared.TypeInt:
115 | intCount++
116 | case shared.TypeFloat:
117 | floatCount++
118 | }
119 | }
120 |
121 | st.variables["global"][name] = shared.Function{
122 | Name: name,
123 | Parameters: params,
124 | Line: line,
125 | Column: column,
126 | StartQuad: -1,
127 | IntVarsCounter: intCount,
128 | FloatVarsCounter: floatCount,
129 | }
130 |
131 | // Add parameters to function scope
132 | for _, param := range params {
133 | st.variables[name][param.Name] = param
134 | }
135 |
136 | return nil
137 | }
138 |
139 | func (st *SymbolTable) IncrementFunctionVarCount(varType shared.Type) error {
140 | if st.currentScope == "global" {
141 | return fmt.Errorf("cannot increment function variable count in global scope")
142 | }
143 |
144 | function, ok := st.variables["global"][st.currentScope].(shared.Function)
145 | if !ok {
146 | return fmt.Errorf("current scope is not a function")
147 | }
148 |
149 | switch varType {
150 | case shared.TypeInt:
151 | function.IntVarsCounter++
152 | case shared.TypeFloat:
153 | function.FloatVarsCounter++
154 | default:
155 | return fmt.Errorf("unsupported variable type for counting")
156 | }
157 |
158 | // Update the function in global scope
159 | st.variables["global"][st.currentScope] = function
160 | return nil
161 | }
162 |
163 | func (st *SymbolTable) GetFunctionVarCounts(functionName string) (int, int, error) {
164 | function, ok := st.variables["global"][functionName].(shared.Function)
165 | if !ok {
166 | return 0, 0, fmt.Errorf("function %s not found", functionName)
167 | }
168 |
169 | return function.IntVarsCounter, function.FloatVarsCounter, nil
170 | }
171 |
172 | func (st *SymbolTable) UpdateFunctionStartQuad(functionName string, start int) error {
173 | function, ok := st.variables["global"][functionName].(shared.Function)
174 | if !ok {
175 | return fmt.Errorf("function %s not found", functionName)
176 | }
177 | function.StartQuad = start
178 |
179 | st.variables["global"][functionName] = function
180 | return nil
181 | }
182 |
183 | func (st *SymbolTable) GetFunctionStartQuad(functionName string) (int, error) {
184 | function, ok := st.variables["global"][functionName].(shared.Function)
185 | if !ok {
186 | return -1, fmt.Errorf("function %s not found", functionName)
187 | }
188 |
189 | return function.StartQuad, nil
190 | }
191 |
192 | // Functionality to be added later :/
193 | //func (st *SymbolTable) UpdateFunctionMemoryRequirements(functionName string) error {
194 | // function, ok := st.variables["global"][functionName].(Function)
195 | // if !ok {
196 | // return fmt.Errorf("function %s not found", functionName)
197 | // }
198 | //
199 | // // Count local variables in function scope
200 | // for _, symbol := range st.variables[functionName] {
201 | // if variable, ok := symbol.(Variable); ok {
202 | // switch variable.Type {
203 | // case shared.TypeInt:
204 | // function.IntVarsCount++
205 | // case shared.TypeFloat:
206 | // function.FloatVarsCount++
207 | // }
208 | // }
209 | // }
210 | //
211 | // // Update function in global scope
212 | // st.variables["global"][functionName] = function
213 | // return nil
214 | //}
215 |
216 | func (st *SymbolTable) ValidateVarAssignment(varName string, line int) error {
217 | if st.variables[st.currentScope] == nil {
218 | st.variables[st.currentScope] = make(map[string]interface{})
219 | }
220 |
221 | if symbol, exists := st.variables[st.currentScope][varName]; exists {
222 | if _, ok := symbol.(shared.Variable); !ok {
223 | return fmt.Errorf("line %d: '%s' is not a variable", line, varName)
224 | }
225 | return nil
226 | }
227 |
228 | // If not in current scope, check global
229 | if st.currentScope != "global" {
230 | if symbol, exists := st.variables["global"][varName]; exists {
231 | if _, ok := symbol.(shared.Variable); !ok {
232 | return fmt.Errorf("line %d: '%s' is not a variable", line, varName)
233 | }
234 | return nil
235 | }
236 | }
237 |
238 | return fmt.Errorf("line %d: undefined variable '%s'", line, varName)
239 | }
240 |
241 | func (st *SymbolTable) ValidateFunctionCall(funcName string, line int, args []shared.Type) error {
242 | symbol, exists := st.variables["global"][funcName]
243 | if !exists {
244 | return fmt.Errorf("line %d: undefined function '%s'", line, funcName)
245 | }
246 |
247 | function, ok := symbol.(shared.Function)
248 | if !ok {
249 | return fmt.Errorf("line %d: '%s' is not a function", line, funcName)
250 | }
251 |
252 | if len(function.Parameters) != len(args) {
253 | fmt.Println(function.Parameters)
254 | fmt.Println(args)
255 | return fmt.Errorf("line %d: function '%s' expects %d arguments but got %d",
256 | line, funcName, len(function.Parameters), len(args))
257 | }
258 |
259 | for i, paramVar := range function.Parameters {
260 | argType := args[i]
261 |
262 | // Direct type match
263 | if paramVar.Type == argType {
264 | continue
265 | }
266 |
267 | // Allow int -> float conversion
268 | if paramVar.Type == shared.TypeFloat && argType == shared.TypeInt {
269 | continue
270 | }
271 |
272 | return fmt.Errorf("line %d: invalid argument type for parameter '%s' in function '%s': expected %s, got %s",
273 | line, paramVar.Name, funcName, paramVar.Type, argType)
274 | }
275 |
276 | return nil
277 | }
278 |
279 | func (st *SymbolTable) ExitFunctionScope() {
280 | st.scopeStack = st.scopeStack[:len(st.scopeStack)-1]
281 | st.currentScope = "global"
282 | }
283 |
284 | func (st *SymbolTable) EnterFunctionScope(name string) error {
285 | if _, exists := st.variables["global"][name]; !exists {
286 | return fmt.Errorf("cannot enter scope of undefined function '%s'", name)
287 | }
288 |
289 | if _, ok := st.variables["global"][name].(shared.Function); !ok {
290 | return fmt.Errorf("'%s' is not a function", name)
291 | }
292 |
293 | // Ensure the function scope map is initialized
294 | if st.variables[name] == nil {
295 | st.variables[name] = make(map[string]interface{})
296 | }
297 |
298 | st.scopeStack = append(st.scopeStack, name)
299 | st.currentScope = name
300 | return nil
301 | }
302 |
303 | func (st *SymbolTable) GetFunctionInfo(functionName string) (*shared.Function, error) {
304 | symbol, exists := st.variables["global"][functionName]
305 | if !exists {
306 | return nil, fmt.Errorf("function %s not found", functionName)
307 | }
308 |
309 | funcInfo, ok := symbol.(shared.Function)
310 | if !ok {
311 | return nil, fmt.Errorf("%s is not a function", functionName)
312 | }
313 |
314 | return &funcInfo, nil
315 | }
316 |
317 | func (st *SymbolTable) GetScope() string {
318 | return st.currentScope
319 | }
320 |
321 | func (st *SymbolTable) PrettyPrint() {
322 | fmt.Println("\n=== Symbol Table ===")
323 |
324 | fmt.Println("\nGlobal Scope:")
325 | fmt.Println("-------------")
326 | for name, symbol := range st.variables["global"] {
327 | switch v := symbol.(type) {
328 | case shared.Variable:
329 | fmt.Printf("Variable: %s\n", name)
330 | fmt.Printf(" Type: %s\n", v.Type)
331 | fmt.Printf(" Line: %d, Column: %d\n", v.Line, v.Column)
332 | case shared.Function:
333 | fmt.Printf("Function: %s\n", name)
334 | fmt.Printf(" Parameters:\n")
335 | if len(v.Parameters) == 0 {
336 | fmt.Printf(" None\n")
337 | }
338 | for _, param := range v.Parameters {
339 | fmt.Printf(" - %s: %s\n", param.Name, param.Type)
340 | }
341 | fmt.Printf(" Line: %d, Column: %d\n", v.Line, v.Column)
342 | fmt.Printf("Size int: %d, float: %d", v.IntVarsCounter, v.FloatVarsCounter)
343 | }
344 | fmt.Println()
345 | }
346 |
347 | // Print other scopes (function scopes)
348 | for scope, symbols := range st.variables {
349 | if scope != "global" {
350 | fmt.Printf("\nFunction Scope: %s\n", scope)
351 | fmt.Println("------------------")
352 | for name, symbol := range symbols {
353 | switch v := symbol.(type) {
354 | case shared.Variable:
355 | fmt.Printf("Variable: %s\n", name)
356 | fmt.Printf(" Type: %s\n", v.Type)
357 | fmt.Printf(" Line: %d, Column: %d\n", v.Line, v.Column)
358 | }
359 | }
360 | fmt.Println()
361 | }
362 | }
363 |
364 | fmt.Println("=== End Symbol Table ===")
365 | }
366 |
367 | func (st *SymbolTable) GetGlobalScope() map[string]interface{} {
368 | return st.variables["global"]
369 | }
370 |
--------------------------------------------------------------------------------
/src/semantic/util.go:
--------------------------------------------------------------------------------
1 | package semantic
2 |
3 | import (
4 | "strconv"
5 | )
6 |
7 | func isNumeric(s string) bool {
8 | _, errInt := strconv.Atoi(s)
9 | _, errFloat := strconv.ParseFloat(s, 64)
10 | return errInt == nil || errFloat == nil
11 | }
12 |
--------------------------------------------------------------------------------
/src/shared/Types.go:
--------------------------------------------------------------------------------
1 | package shared
2 |
3 | type Type int
4 |
5 | const (
6 | TypeInt Type = iota
7 | TypeFloat
8 | TypeString
9 | TypeError
10 | )
11 |
12 | func (t Type) String() string {
13 | switch t {
14 | case TypeInt:
15 | return "int"
16 | case TypeFloat:
17 | return "float"
18 | case TypeString:
19 | return "string"
20 | default:
21 | return "error"
22 | }
23 | }
24 |
25 | type Variable struct {
26 | Name string
27 | Type Type
28 | Line int
29 | Column int
30 | Address int
31 | }
32 |
33 | type Function struct {
34 | Name string
35 | Parameters []Variable
36 | Line int
37 | Column int
38 | StartQuad int
39 | IntVarsCounter int
40 | FloatVarsCounter int
41 | }
42 |
43 | type FunctionInfo struct {
44 | Name string
45 | StartQuad int
46 | IntVarsCount int
47 | FloatVarsCount int
48 | Parameters []Variable
49 | }
50 |
51 | type Stack struct {
52 | items []interface{}
53 | }
54 |
55 | func NewStack() *Stack {
56 | return &Stack{
57 | items: make([]interface{}, 0),
58 | }
59 | }
60 |
61 | func (s *Stack) Push(item interface{}) {
62 | s.items = append(s.items, item)
63 | }
64 |
65 | func (s *Stack) Pop() interface{} {
66 | if len(s.items) == 0 {
67 | return nil
68 | }
69 | item := s.items[len(s.items)-1]
70 | s.items = s.items[:len(s.items)-1]
71 | return item
72 | }
73 |
74 | func (s *Stack) Top() interface{} {
75 | if len(s.items) == 0 {
76 | return nil
77 | }
78 | return s.items[len(s.items)-1]
79 | }
80 |
81 | func (s *Stack) IsEmpty() bool {
82 | return len(s.items) == 0
83 | }
84 |
85 | func (s *Stack) Size() int {
86 | return len(s.items)
87 | }
88 |
89 | type Quadruple struct {
90 | Operator string // The operation to be performed
91 | LeftOp interface{} // Left operand
92 | RightOp interface{} // Right operand
93 | Result interface{} // Where the result will be stored
94 | }
95 |
--------------------------------------------------------------------------------
/src/storer/Serializer.go:
--------------------------------------------------------------------------------
1 | package storer
2 |
3 | import (
4 | "encoding/gob"
5 | "fmt"
6 | "os"
7 | "pogo/src/semantic"
8 | "pogo/src/shared"
9 | "pogo/src/virtualmachine"
10 | )
11 |
12 | type SerializedVMData struct {
13 | Quadruples []shared.Quadruple
14 | Functions map[string]shared.FunctionInfo
15 | MemoryManager *virtualmachine.MemoryManager
16 | }
17 |
18 | func SaveCompiledData(quads []shared.Quadruple, SymbolTable *semantic.SymbolTable, memoryManager *virtualmachine.MemoryManager, filename string) error {
19 | functions := make(map[string]shared.FunctionInfo)
20 | for name, symbol := range SymbolTable.GetGlobalScope() {
21 | if function, ok := symbol.(shared.Function); ok {
22 | functions[name] = shared.FunctionInfo{
23 | Name: function.Name,
24 | StartQuad: function.StartQuad,
25 | IntVarsCount: function.IntVarsCounter,
26 | FloatVarsCount: function.FloatVarsCounter,
27 | Parameters: function.Parameters,
28 | }
29 | }
30 | }
31 |
32 | vmData := SerializedVMData{
33 | Quadruples: quads,
34 | Functions: functions,
35 | MemoryManager: memoryManager,
36 | }
37 |
38 | file, err := os.Create(filename)
39 | if err != nil {
40 | return fmt.Errorf("error creating output file: %v", err)
41 | }
42 | defer file.Close()
43 |
44 | encoder := gob.NewEncoder(file)
45 | if err := encoder.Encode(vmData); err != nil {
46 | // return fmt.Errorf("error encoding data: %v", err)
47 | }
48 |
49 | return nil
50 | }
51 |
52 | func LoadCompiledData(filename string) (*virtualmachine.VirtualMachine, error) {
53 |
54 | file, err := os.Open(filename)
55 | if err != nil {
56 | return nil, fmt.Errorf("error opening file: %v", err)
57 | }
58 | defer file.Close()
59 |
60 | decoder := gob.NewDecoder(file)
61 |
62 | var vmData SerializedVMData
63 | if err := decoder.Decode(&vmData); err != nil {
64 | return nil, fmt.Errorf("error decoding data: %v", err)
65 | }
66 |
67 | memManager := vmData.MemoryManager
68 | vm := virtualmachine.NewVirtualMachine(vmData.Quadruples, memManager)
69 |
70 | vm.Functions = vmData.Functions
71 |
72 | return vm, nil
73 | }
74 |
--------------------------------------------------------------------------------
/src/token/context.go:
--------------------------------------------------------------------------------
1 | // Code generated by gocc; DO NOT EDIT.
2 |
3 | package token
4 |
5 | // Context allows user-defined data to be associated with the
6 | // lexer/scanner to be associated with each token that lexer
7 | // produces.
8 | type Context interface{}
9 |
10 | // Sourcer is a Context interface which presents a Source() method
11 | // identifying e.g the filename for the current code.
12 | type Sourcer interface {
13 | Source() string
14 | }
15 |
--------------------------------------------------------------------------------
/src/token/token.go:
--------------------------------------------------------------------------------
1 | // Code generated by gocc; DO NOT EDIT.
2 |
3 | package token
4 |
5 | import (
6 | "bytes"
7 | "fmt"
8 | "strconv"
9 | "unicode/utf8"
10 | )
11 |
12 | type Token struct {
13 | Type
14 | Lit []byte
15 | Pos
16 | }
17 |
18 | type Type int
19 |
20 | const (
21 | INVALID Type = iota
22 | EOF
23 | )
24 |
25 | type Pos struct {
26 | Offset int
27 | Line int
28 | Column int
29 | Context Context
30 | }
31 |
32 | func (p Pos) String() string {
33 | // If the context provides a filename, provide a human-readable File:Line:Column representation.
34 | switch src := p.Context.(type) {
35 | case Sourcer:
36 | return fmt.Sprintf("%s:%d:%d", src.Source(), p.Line, p.Column)
37 | default:
38 | return fmt.Sprintf("Pos(offset=%d, line=%d, column=%d)", p.Offset, p.Line, p.Column)
39 | }
40 | }
41 |
42 | type TokenMap struct {
43 | typeMap []string
44 | idMap map[string]Type
45 | }
46 |
47 | func (m TokenMap) Id(tok Type) string {
48 | if int(tok) < len(m.typeMap) {
49 | return m.typeMap[tok]
50 | }
51 | return "unknown"
52 | }
53 |
54 | func (m TokenMap) Type(tok string) Type {
55 | if typ, exist := m.idMap[tok]; exist {
56 | return typ
57 | }
58 | return INVALID
59 | }
60 |
61 | func (m TokenMap) TokenString(tok *Token) string {
62 | return fmt.Sprintf("%s(%d,%s)", m.Id(tok.Type), tok.Type, tok.Lit)
63 | }
64 |
65 | func (m TokenMap) StringType(typ Type) string {
66 | return fmt.Sprintf("%s(%d)", m.Id(typ), typ)
67 | }
68 |
69 | // Equals returns returns true if the token Type and Lit are matches.
70 | func (t *Token) Equals(rhs interface{}) bool {
71 | switch rhsT := rhs.(type) {
72 | case *Token:
73 | return t == rhsT || (t.Type == rhsT.Type && bytes.Equal(t.Lit, rhsT.Lit))
74 | default:
75 | return false
76 | }
77 | }
78 |
79 | // CharLiteralValue returns the string value of the char literal.
80 | func (t *Token) CharLiteralValue() string {
81 | return string(t.Lit[1 : len(t.Lit)-1])
82 | }
83 |
84 | // Float32Value returns the float32 value of the token or an error if the token literal does not
85 | // denote a valid float32.
86 | func (t *Token) Float32Value() (float32, error) {
87 | if v, err := strconv.ParseFloat(string(t.Lit), 32); err != nil {
88 | return 0, err
89 | } else {
90 | return float32(v), nil
91 | }
92 | }
93 |
94 | // Float64Value returns the float64 value of the token or an error if the token literal does not
95 | // denote a valid float64.
96 | func (t *Token) Float64Value() (float64, error) {
97 | return strconv.ParseFloat(string(t.Lit), 64)
98 | }
99 |
100 | // IDValue returns the string representation of an identifier token.
101 | func (t *Token) IDValue() string {
102 | return string(t.Lit)
103 | }
104 |
105 | // Int32Value returns the int32 value of the token or an error if the token literal does not
106 | // denote a valid float64.
107 | func (t *Token) Int32Value() (int32, error) {
108 | if v, err := strconv.ParseInt(string(t.Lit), 10, 64); err != nil {
109 | return 0, err
110 | } else {
111 | return int32(v), nil
112 | }
113 | }
114 |
115 | // Int64Value returns the int64 value of the token or an error if the token literal does not
116 | // denote a valid float64.
117 | func (t *Token) Int64Value() (int64, error) {
118 | return strconv.ParseInt(string(t.Lit), 10, 64)
119 | }
120 |
121 | // UTF8Rune decodes the UTF8 rune in the token literal. It returns utf8.RuneError if
122 | // the token literal contains an invalid rune.
123 | func (t *Token) UTF8Rune() (rune, error) {
124 | r, _ := utf8.DecodeRune(t.Lit)
125 | if r == utf8.RuneError {
126 | err := fmt.Errorf("Invalid rune")
127 | return r, err
128 | }
129 | return r, nil
130 | }
131 |
132 | // StringValue returns the string value of the token literal.
133 | func (t *Token) StringValue() string {
134 | return string(t.Lit[1 : len(t.Lit)-1])
135 | }
136 |
137 | var TokMap = TokenMap{
138 | typeMap: []string{
139 | "INVALID",
140 | "␚",
141 | "assignOp",
142 | "closeBrace",
143 | "closeParan",
144 | "expressionOp",
145 | "floatLit",
146 | "id",
147 | "intLit",
148 | "kwdBegin",
149 | "kwdElse",
150 | "kwdEnd",
151 | "kwdFunc",
152 | "kwdIf",
153 | "kwdPrint",
154 | "kwdProgram",
155 | "kwdVars",
156 | "kwdWhile",
157 | "openBrace",
158 | "openParan",
159 | "relOp",
160 | "repeatTerminator",
161 | "stringLit",
162 | "termOp",
163 | "terminator",
164 | "type",
165 | "typeAssignOp",
166 | },
167 |
168 | idMap: map[string]Type{
169 | "INVALID": 0,
170 | "␚": 1,
171 | "assignOp": 2,
172 | "closeBrace": 3,
173 | "closeParan": 4,
174 | "expressionOp": 5,
175 | "floatLit": 6,
176 | "id": 7,
177 | "intLit": 8,
178 | "kwdBegin": 9,
179 | "kwdElse": 10,
180 | "kwdEnd": 11,
181 | "kwdFunc": 12,
182 | "kwdIf": 13,
183 | "kwdPrint": 14,
184 | "kwdProgram": 15,
185 | "kwdVars": 16,
186 | "kwdWhile": 17,
187 | "openBrace": 18,
188 | "openParan": 19,
189 | "relOp": 20,
190 | "repeatTerminator": 21,
191 | "stringLit": 22,
192 | "termOp": 23,
193 | "terminator": 24,
194 | "type": 25,
195 | "typeAssignOp": 26,
196 | },
197 | }
198 |
--------------------------------------------------------------------------------
/src/util/litconv.go:
--------------------------------------------------------------------------------
1 | // Code generated by gocc; DO NOT EDIT.
2 |
3 | package util
4 |
5 | import (
6 | "fmt"
7 | "strconv"
8 | "unicode"
9 | "unicode/utf8"
10 | )
11 |
12 | // Interface.
13 |
14 | // RuneValue will convert the literal value of a scanned token to a rune.
15 | func RuneValue(lit []byte) rune {
16 | if lit[1] == '\\' {
17 | return escapeCharVal(lit)
18 | }
19 | r, size := utf8.DecodeRune(lit[1:])
20 | if size != len(lit)-2 {
21 | panic(fmt.Sprintf("Error decoding rune. Lit: %s, rune: %d, size%d\n", lit, r, size))
22 | }
23 | return r
24 | }
25 |
26 | // UintValue will attempt to parse a byte-slice as a signed base-10 64-bit integer.
27 | func IntValue(lit []byte) (int64, error) {
28 | return strconv.ParseInt(string(lit), 10, 64)
29 | }
30 |
31 | // UintValue will attempt to parse a byte-slice as an unsigned base-10 64-bit integer.
32 | func UintValue(lit []byte) (uint64, error) {
33 | return strconv.ParseUint(string(lit), 10, 64)
34 | }
35 |
36 | // Helpers.
37 | func escapeCharVal(lit []byte) rune {
38 | var i, base, max uint32
39 | offset := 2
40 | switch lit[offset] {
41 | case 'a':
42 | return '\a'
43 | case 'b':
44 | return '\b'
45 | case 'f':
46 | return '\f'
47 | case 'n':
48 | return '\n'
49 | case 'r':
50 | return '\r'
51 | case 't':
52 | return '\t'
53 | case 'v':
54 | return '\v'
55 | case '\\':
56 | return '\\'
57 | case '\'':
58 | return '\''
59 | case '0', '1', '2', '3', '4', '5', '6', '7':
60 | i, base, max = 3, 8, 255
61 | case 'x':
62 | i, base, max = 2, 16, 255
63 | offset++
64 | case 'u':
65 | i, base, max = 4, 16, unicode.MaxRune
66 | offset++
67 | case 'U':
68 | i, base, max = 8, 16, unicode.MaxRune
69 | offset++
70 | default:
71 | panic(fmt.Sprintf("Error decoding character literal: %s\n", lit))
72 | }
73 |
74 | var x uint32
75 | for ; i > 0 && offset < len(lit)-1; i-- {
76 | ch, size := utf8.DecodeRune(lit[offset:])
77 | offset += size
78 | d := uint32(digitVal(ch))
79 | if d >= base {
80 | panic(fmt.Sprintf("charVal(%s): illegal character (%c) in escape sequence. size=%d, offset=%d", lit, ch, size, offset))
81 | }
82 | x = x*base + d
83 | }
84 | if x > max || 0xD800 <= x && x < 0xE000 {
85 | panic(fmt.Sprintf("Error decoding escape char value. Lit:%s, offset:%d, escape sequence is invalid Unicode code point\n", lit, offset))
86 | }
87 |
88 | return rune(x)
89 | }
90 |
91 | func digitVal(ch rune) int {
92 | switch {
93 | case '0' <= ch && ch <= '9':
94 | return int(ch) - '0'
95 | case 'a' <= ch && ch <= 'f':
96 | return int(ch) - 'a' + 10
97 | case 'A' <= ch && ch <= 'F':
98 | return int(ch) - 'A' + 10
99 | }
100 | return 16 // larger than any legal digit val
101 | }
102 |
--------------------------------------------------------------------------------
/src/util/rune.go:
--------------------------------------------------------------------------------
1 | // Code generated by gocc; DO NOT EDIT.
2 |
3 | package util
4 |
5 | import (
6 | "fmt"
7 | )
8 |
9 | func RuneToString(r rune) string {
10 | if r >= 0x20 && r < 0x7f {
11 | return fmt.Sprintf("'%c'", r)
12 | }
13 | switch r {
14 | case 0x07:
15 | return "'\\a'"
16 | case 0x08:
17 | return "'\\b'"
18 | case 0x0C:
19 | return "'\\f'"
20 | case 0x0A:
21 | return "'\\n'"
22 | case 0x0D:
23 | return "'\\r'"
24 | case 0x09:
25 | return "'\\t'"
26 | case 0x0b:
27 | return "'\\v'"
28 | case 0x5c:
29 | return "'\\\\\\'"
30 | case 0x27:
31 | return "'\\''"
32 | case 0x22:
33 | return "'\\\"'"
34 | }
35 | if r < 0x10000 {
36 | return fmt.Sprintf("\\u%04x", r)
37 | }
38 | return fmt.Sprintf("\\U%08x", r)
39 | }
40 |
--------------------------------------------------------------------------------
/src/virtualmachine/Memory.go:
--------------------------------------------------------------------------------
1 | package virtualmachine
2 |
3 | import (
4 | "fmt"
5 | "pogo/src/shared"
6 | "strconv"
7 | )
8 |
9 | const (
10 | GLOBAL_START = 0
11 | LOCAL_START = 4000
12 | TEMP_START = 8000
13 | CONSTANT_START = 12000
14 |
15 | GLOBAL_INT_START = 0
16 | GLOBAL_INT_END = 1999
17 | GLOBAL_FLOAT_START = 2000
18 | GLOBAL_FLOAT_END = 3999
19 |
20 | LOCAL_INT_START = 4000
21 | LOCAL_INT_END = 5999
22 | LOCAL_FLOAT_START = 6000
23 | LOCAL_FLOAT_END = 7999
24 |
25 | TEMP_INT_START = 8000
26 | TEMP_INT_END = 9999
27 | TEMP_FLOAT_START = 10000
28 | TEMP_FLOAT_END = 11999
29 |
30 | CONSTANT_INT_START = 12000
31 | CONSTANT_INT_END = 12999
32 | CONSTANT_FLOAT_START = 13000
33 | CONSTANT_FLOAT_END = 13999
34 | CONSTANT_STR_START = 14000
35 | CONSTANT_STR_END = 15999
36 |
37 | MEMORY_SEGMENT_SIZE = 4000
38 | TOTAL_MEMORY_SIZE = 16000
39 | )
40 |
41 | type FunctionMemorySegment struct {
42 | localMemory []interface{}
43 | localIntPtr int
44 | localFloatPtr int
45 | intVarsCount int
46 | floatVarsCount int
47 | }
48 |
49 | type MemoryManager struct {
50 | globalMemory []interface{}
51 | GlobalIntPtr int
52 | GlobalFloatPtr int
53 |
54 | tempMemory []interface{}
55 | TempIntPtr int
56 | TempFloatPtr int
57 |
58 | constantIntPtr int
59 | constantFloatPtr int
60 | constantStrPtr int
61 |
62 | // map for constant reusing / not restoring the same constant
63 | ConstantMapLoad map[int]interface{}
64 | ConstantMapStore map[interface{}]int
65 |
66 | memoryStack []FunctionMemorySegment
67 | currentSegment *FunctionMemorySegment
68 | }
69 |
70 | func NewMemoryManager() *MemoryManager {
71 | return &MemoryManager{
72 | GlobalIntPtr: GLOBAL_INT_START,
73 | GlobalFloatPtr: GLOBAL_FLOAT_START,
74 | TempIntPtr: TEMP_INT_START,
75 | TempFloatPtr: TEMP_FLOAT_START,
76 | constantIntPtr: CONSTANT_INT_START,
77 | constantFloatPtr: CONSTANT_FLOAT_START,
78 | constantStrPtr: CONSTANT_STR_START,
79 | ConstantMapLoad: make(map[int]interface{}),
80 | ConstantMapStore: make(map[interface{}]int),
81 | memoryStack: make([]FunctionMemorySegment, 0),
82 | currentSegment: nil,
83 | }
84 | }
85 |
86 | func (mm *MemoryManager) InitializeMemory() {
87 | globalFloat := mm.GlobalFloatPtr
88 | globalInt := mm.GlobalIntPtr
89 | globalSize := globalFloat + globalInt
90 |
91 | tempInt := mm.TempIntPtr
92 | tempFloat := mm.TempFloatPtr
93 | tempSize := tempInt + tempFloat
94 |
95 | mm.globalMemory = make([]interface{}, globalSize)
96 | mm.tempMemory = make([]interface{}, tempSize)
97 | }
98 |
99 | func (mm *MemoryManager) AllocateGlobal(varType shared.Type) (int, error) {
100 | switch varType {
101 | case shared.TypeInt:
102 | if mm.GlobalIntPtr >= GLOBAL_INT_END {
103 | return -1, fmt.Errorf("global integer memory overflow")
104 | }
105 | addr := mm.GlobalIntPtr
106 | mm.GlobalIntPtr++
107 | return addr, nil
108 | case shared.TypeFloat:
109 | if mm.GlobalFloatPtr >= GLOBAL_FLOAT_END {
110 | return -1, fmt.Errorf("global float memory overflow")
111 | }
112 | addr := mm.GlobalFloatPtr
113 | mm.GlobalFloatPtr++
114 | return addr, nil
115 | default:
116 | return -1, fmt.Errorf("unsupported type for global allocation")
117 | }
118 | }
119 |
120 | func (mm *MemoryManager) AllocateTemp(varType shared.Type) (int, error) {
121 | switch varType {
122 | case shared.TypeInt:
123 | if mm.TempIntPtr >= TEMP_INT_END {
124 | return -1, fmt.Errorf("temporary integer memory overflow")
125 | }
126 | addr := mm.TempIntPtr
127 | mm.TempIntPtr++
128 | return addr, nil
129 | case shared.TypeFloat:
130 | if mm.TempFloatPtr >= TEMP_FLOAT_END {
131 | return -1, fmt.Errorf("temporary float memory overflow")
132 | }
133 | addr := mm.TempFloatPtr
134 | mm.TempFloatPtr++
135 | return addr, nil
136 | default:
137 | return -1, fmt.Errorf("unsupported type for temporary allocation")
138 | }
139 | }
140 |
141 | func (mm *MemoryManager) AllocateConstant(value string) (int, error) {
142 | if addr, exists := mm.ConstantMapStore[value]; exists {
143 | return addr, nil
144 | }
145 |
146 | if intVal, ok := strconv.Atoi(value); ok == nil {
147 | if mm.constantIntPtr >= CONSTANT_INT_END {
148 | return -1, fmt.Errorf("constant integer memory overflow")
149 | }
150 | addr := mm.constantIntPtr
151 | // fmt.Println("Allocating value ", intVal, "at ", addr-CONSTANT_START)
152 | mm.ConstantMapLoad[addr-CONSTANT_START] = intVal
153 | mm.ConstantMapStore[value] = addr
154 | mm.constantIntPtr++
155 | return addr, nil
156 | }
157 |
158 | if floatVal, ok := strconv.ParseFloat(value, 64); ok == nil {
159 | if mm.constantFloatPtr >= CONSTANT_FLOAT_END {
160 | return -1, fmt.Errorf("constant integer memory overflow")
161 | }
162 | addr := mm.constantFloatPtr
163 | mm.ConstantMapLoad[addr-CONSTANT_START] = floatVal
164 | mm.ConstantMapStore[value] = addr
165 | mm.constantFloatPtr++
166 | return addr, nil
167 | }
168 |
169 | return -1, fmt.Errorf("invalid constant value: %s", value)
170 | }
171 |
172 | func (mm *MemoryManager) AllocateLocal(varType shared.Type) (int, error) {
173 | switch varType {
174 | case shared.TypeInt:
175 | if mm.currentSegment.localIntPtr >= LOCAL_INT_END {
176 | return -1, fmt.Errorf("local integer memory overflow")
177 | }
178 | addr := mm.currentSegment.localIntPtr
179 | mm.currentSegment.localIntPtr++
180 | return addr, nil
181 |
182 | case shared.TypeFloat:
183 | if mm.currentSegment.localFloatPtr >= LOCAL_FLOAT_END {
184 | return -1, fmt.Errorf("local float memory overflow")
185 | }
186 | addr := mm.currentSegment.localFloatPtr
187 | mm.currentSegment.localFloatPtr++
188 | return addr, nil
189 |
190 | default:
191 | return -1, fmt.Errorf("unsupported type for local allocation")
192 | }
193 | }
194 |
195 | func (mm *MemoryManager) AllocateStringAddress(value string) (int, error) {
196 | if addr, exists := mm.ConstantMapStore[value]; exists {
197 | return addr, nil
198 | }
199 |
200 | if mm.constantStrPtr >= CONSTANT_STR_END {
201 | return -1, fmt.Errorf("string constant memory overflow")
202 | }
203 |
204 | addr := mm.constantStrPtr
205 |
206 | // Store the string in constant memory
207 | offset := addr - CONSTANT_START
208 | mm.ConstantMapLoad[offset] = value
209 |
210 | // Add to map and increment pointer
211 | mm.ConstantMapStore[value] = addr
212 | mm.constantStrPtr++
213 | return addr, nil
214 | }
215 |
216 | func (mm *MemoryManager) Store(address int, value interface{}) error {
217 | if address < 0 || address >= TOTAL_MEMORY_SIZE {
218 | return fmt.Errorf("memory access out of bounds: %d", address)
219 | }
220 | // fmt.Println("entered here: with address ", address, "and ", value)
221 |
222 | var segment *[]interface{}
223 | var offset int
224 |
225 | if address >= LOCAL_START && address < LOCAL_START+MEMORY_SEGMENT_SIZE {
226 | if address < LOCAL_FLOAT_START {
227 | offset = address - LOCAL_START
228 | } else {
229 | offset = address - LOCAL_FLOAT_START + mm.currentSegment.intVarsCount
230 | }
231 |
232 | if mm.currentSegment == nil {
233 | return fmt.Errorf("no active function segment")
234 | }
235 |
236 | if offset >= len(mm.currentSegment.localMemory) {
237 | return fmt.Errorf("local memory access out of bounds: %d", address)
238 | }
239 | // Store directly in the dynamic local memory
240 | mm.currentSegment.localMemory[offset] = value
241 | return nil
242 | }
243 |
244 | switch {
245 | case address >= TEMP_START && address < TEMP_START+MEMORY_SEGMENT_SIZE:
246 | segment = &mm.tempMemory
247 | if address >= TEMP_INT_START && address < TEMP_FLOAT_START {
248 | offset = address - TEMP_START
249 | } else if address >= TEMP_FLOAT_START {
250 | offset = address - TEMP_FLOAT_START + mm.TempIntPtr
251 | }
252 | case address >= GLOBAL_START && address < GLOBAL_START+MEMORY_SEGMENT_SIZE:
253 | segment = &mm.globalMemory
254 | if address >= GLOBAL_INT_START && address < GLOBAL_FLOAT_START {
255 | offset = address - GLOBAL_START
256 | } else if address >= GLOBAL_FLOAT_START {
257 | offset = address - GLOBAL_FLOAT_START + mm.GlobalIntPtr
258 | }
259 | default:
260 | return fmt.Errorf("invalid memory address: %d", address)
261 | }
262 |
263 | (*segment)[offset] = value
264 | return nil
265 | }
266 |
267 | func (mm *MemoryManager) Load(address int) (interface{}, error) {
268 | if address < 0 || address >= TOTAL_MEMORY_SIZE {
269 | return nil, fmt.Errorf("memory access out of bounds: %d", address)
270 | }
271 |
272 | var segment *[]interface{}
273 | var offset int
274 |
275 | if address >= LOCAL_START && address < LOCAL_START+MEMORY_SEGMENT_SIZE {
276 | if address < LOCAL_FLOAT_START {
277 | offset = address - LOCAL_START
278 | } else {
279 | offset = (address - LOCAL_FLOAT_START) + mm.currentSegment.intVarsCount
280 | }
281 |
282 | if mm.currentSegment == nil {
283 | return nil, fmt.Errorf("no active function segment")
284 | }
285 | if offset >= len(mm.currentSegment.localMemory) {
286 | return nil, fmt.Errorf("local memory access out of bounds: %d", address)
287 | }
288 | value := mm.currentSegment.localMemory[offset]
289 | if value == nil {
290 | return nil, fmt.Errorf("accessing uninitialized memory at address %d", address)
291 | }
292 | return value, nil
293 | }
294 |
295 | switch {
296 | case address >= CONSTANT_START && address < CONSTANT_START+MEMORY_SEGMENT_SIZE:
297 | offset := address - CONSTANT_START
298 | if _, exists := mm.ConstantMapLoad[offset]; !exists {
299 | return nil, fmt.Errorf("trying to retrieve from uninitialized memory address")
300 | }
301 | return mm.ConstantMapLoad[offset], nil
302 | case address >= TEMP_START && address < TEMP_START+MEMORY_SEGMENT_SIZE:
303 | segment = &mm.tempMemory
304 | if address >= TEMP_INT_START && address < TEMP_FLOAT_START {
305 | offset = address - TEMP_START
306 | } else if address >= TEMP_FLOAT_START {
307 | offset = address - TEMP_FLOAT_START + mm.TempIntPtr
308 | }
309 | case address >= GLOBAL_START && address < MEMORY_SEGMENT_SIZE:
310 | segment = &mm.globalMemory
311 | if address >= GLOBAL_INT_START && address < GLOBAL_FLOAT_START {
312 | offset = address - GLOBAL_START
313 | } else if address >= GLOBAL_FLOAT_START {
314 | offset = address - GLOBAL_FLOAT_START + mm.GlobalIntPtr
315 | }
316 | default:
317 | return nil, fmt.Errorf("invalid memory address: %d", address)
318 | }
319 |
320 | value := (*segment)[offset]
321 | if value == nil {
322 | return nil, fmt.Errorf("accessing uninitialized memory at address %d", address)
323 | }
324 |
325 | return value, nil
326 | }
327 |
328 | func (mm *MemoryManager) PushNewFunctionSegment(isFixed bool, intCount, floatCount int) {
329 | var size int
330 | if isFixed {
331 | size = MEMORY_SEGMENT_SIZE // This is only during function declaration
332 | } else {
333 | size = intCount + floatCount
334 | }
335 |
336 | newSegment := FunctionMemorySegment{
337 | localMemory: make([]interface{}, size),
338 | localIntPtr: LOCAL_INT_START,
339 | localFloatPtr: LOCAL_FLOAT_START,
340 | intVarsCount: intCount,
341 | floatVarsCount: floatCount,
342 | }
343 |
344 | mm.memoryStack = append(mm.memoryStack, newSegment)
345 | mm.currentSegment = &mm.memoryStack[len(mm.memoryStack)-1]
346 | }
347 |
348 | func (mm *MemoryManager) PopFunctionSegment() error {
349 | if len(mm.memoryStack) == 0 {
350 | return fmt.Errorf("no function segments to pop")
351 | }
352 |
353 | mm.memoryStack = mm.memoryStack[:len(mm.memoryStack)-1]
354 |
355 | if len(mm.memoryStack) > 0 {
356 | mm.currentSegment = &mm.memoryStack[len(mm.memoryStack)-1]
357 | } else {
358 | mm.currentSegment = nil
359 | }
360 |
361 | return nil
362 | }
363 |
--------------------------------------------------------------------------------
/src/virtualmachine/VirtualMachine.go:
--------------------------------------------------------------------------------
1 | package virtualmachine
2 |
3 | import (
4 | "fmt"
5 | "pogo/src/shared"
6 | "strings"
7 | )
8 |
9 | type VirtualMachine struct {
10 | quads []shared.Quadruple
11 | memoryManager *MemoryManager
12 | Functions map[string]shared.FunctionInfo
13 | instructionPointer int
14 | returnPointer *shared.Stack
15 | functionStack *shared.Stack
16 | }
17 |
18 | func NewVirtualMachine(quads []shared.Quadruple, memManager *MemoryManager) *VirtualMachine {
19 | vm := &VirtualMachine{
20 | quads: quads,
21 | memoryManager: memManager,
22 | instructionPointer: 0,
23 | returnPointer: shared.NewStack(),
24 | functionStack: shared.NewStack(),
25 | Functions: make(map[string]shared.FunctionInfo),
26 | }
27 |
28 | return vm
29 | }
30 |
31 | func (vm *VirtualMachine) Execute() error {
32 | //fmt.Println("These are the quads", vm.quads)
33 | // fmt.Println("These are the functions", vm.Functions)
34 | // vm.memoryManager.InitializeMemory()
35 | vm.memoryManager.InitializeMemory()
36 | for vm.instructionPointer < len(vm.quads) {
37 | quad := vm.quads[vm.instructionPointer]
38 |
39 | if err := vm.executeQuadruple(quad); err != nil {
40 | return fmt.Errorf("error at instruction %d: %v", vm.instructionPointer, err)
41 | }
42 |
43 | vm.instructionPointer++
44 | }
45 | return nil
46 | }
47 |
48 | func (vm *VirtualMachine) executeQuadruple(quad shared.Quadruple) error {
49 | switch quad.Operator {
50 | case "+", "-", "*", "/":
51 | // fmt.Println("Entering with", quad.Operator)
52 | return vm.executeArithmetic(quad)
53 | case "=":
54 | return vm.executeAssignment(quad)
55 | case "<", ">", "==", "!=":
56 | return vm.executeComparison(quad)
57 | case "print":
58 | return vm.executePrint(quad)
59 | case "goto":
60 | return vm.executeGoto(quad)
61 | case "gotof":
62 | return vm.executeGotoF(quad)
63 | case "gosub":
64 | return vm.executeGosub(quad)
65 | case "era":
66 | return vm.executeEra(quad)
67 | case "endproc":
68 | return vm.executeEndproc(quad)
69 | case "param":
70 | return vm.executeParam(quad)
71 | }
72 |
73 | return nil
74 | }
75 |
76 | func (vm *VirtualMachine) executeArithmetic(quad shared.Quadruple) error {
77 | leftVal, err := vm.memoryManager.Load(quad.LeftOp.(int))
78 |
79 | if err != nil {
80 | return fmt.Errorf("failed to load left operand: %v", err)
81 | }
82 |
83 | rightVal, err := vm.memoryManager.Load(quad.RightOp.(int))
84 | if err != nil {
85 | return fmt.Errorf("failed to load right operand: %v", err)
86 | }
87 |
88 | var result interface{}
89 | var leftFloat, rightFloat float64
90 | isFloatOperation := false
91 |
92 | switch l := leftVal.(type) {
93 | case int:
94 | leftFloat = float64(l)
95 | case float64:
96 | leftFloat = l
97 | isFloatOperation = true
98 | default:
99 | return fmt.Errorf("invalid left operand type: %T", leftVal)
100 | }
101 |
102 | switch r := rightVal.(type) {
103 | case int:
104 | rightFloat = float64(r)
105 | case float64:
106 | rightFloat = r
107 | isFloatOperation = true
108 | default:
109 | return fmt.Errorf("invalid right operand type: %T", rightVal)
110 | }
111 |
112 | var floatResult float64
113 | switch quad.Operator {
114 | case "+":
115 | floatResult = leftFloat + rightFloat
116 | case "-":
117 | floatResult = leftFloat - rightFloat
118 | case "*":
119 | floatResult = leftFloat * rightFloat
120 | case "/":
121 | if rightFloat == 0 {
122 | return fmt.Errorf("division by zero")
123 | }
124 | floatResult = leftFloat / rightFloat
125 | isFloatOperation = true // Division always returns float
126 | default:
127 | return fmt.Errorf("unknown arithmetic operator: %s", quad.Operator)
128 | }
129 |
130 | if isFloatOperation {
131 | result = floatResult
132 | } else {
133 | result = int(floatResult)
134 | }
135 |
136 | return vm.memoryManager.Store(quad.Result.(int), result)
137 | }
138 |
139 | func (vm *VirtualMachine) executeAssignment(quad shared.Quadruple) error {
140 | value, err := vm.memoryManager.Load(quad.LeftOp.(int))
141 | if err != nil {
142 | return fmt.Errorf("failed to load source value: %v", err)
143 | }
144 |
145 | return vm.memoryManager.Store(quad.Result.(int), value)
146 | }
147 |
148 | func (vm *VirtualMachine) executeComparison(quad shared.Quadruple) error {
149 | // fmt.Println("Entering execution")
150 | leftVal, err := vm.memoryManager.Load(quad.LeftOp.(int))
151 |
152 | if err != nil {
153 | return fmt.Errorf("failed to load left operand: %v", err)
154 | }
155 |
156 | rightVal, err := vm.memoryManager.Load(quad.RightOp.(int))
157 | if err != nil {
158 | return fmt.Errorf("failed to load right operand: %v", err)
159 | }
160 | // fmt.Println("This is the rightVal", rightVal)
161 |
162 | var leftFloat, rightFloat float64
163 |
164 | switch v := leftVal.(type) {
165 | case int:
166 | leftFloat = float64(v)
167 | case float64:
168 | leftFloat = v
169 | default:
170 | return fmt.Errorf("invalid type for comparison: %T", leftVal)
171 | }
172 |
173 | switch v := rightVal.(type) {
174 | case int:
175 | rightFloat = float64(v)
176 | case float64:
177 | rightFloat = v
178 | default:
179 | return fmt.Errorf("invalid type for comparison: %T", rightVal)
180 | }
181 |
182 | var result bool
183 | var intResult int
184 |
185 | switch quad.Operator {
186 | case "<":
187 | result = leftFloat < rightFloat
188 | case ">":
189 | result = leftFloat > rightFloat
190 | case "==":
191 | result = leftFloat == rightFloat
192 | case "!=":
193 | result = leftFloat != rightFloat
194 | }
195 |
196 | if result {
197 | intResult = 1
198 | } else {
199 | intResult = 0
200 | }
201 | // fmt.Println("This is where we store", quad.Result)
202 | return vm.memoryManager.Store(quad.Result.(int), intResult)
203 | }
204 |
205 | func (vm *VirtualMachine) executePrint(quad shared.Quadruple) error {
206 | items := quad.LeftOp.([]int)
207 | for i, item := range items {
208 | value, err := vm.memoryManager.Load(item)
209 | if err != nil {
210 | return fmt.Errorf("failed to load print value: %v", err)
211 | }
212 |
213 | switch v := value.(type) {
214 | case string:
215 | cleanStr := strings.Trim(v, "\"")
216 | fmt.Print(cleanStr, " ")
217 | case int:
218 | fmt.Print(v, " ")
219 | case float64:
220 | fmt.Printf("%.2f ", v)
221 | default:
222 | return fmt.Errorf("unsupported type for printing: %T", value)
223 | }
224 |
225 | if i == len(items)-1 {
226 | fmt.Println()
227 | }
228 | }
229 | return nil
230 | }
231 |
232 | func (vm *VirtualMachine) executeGoto(quad shared.Quadruple) error {
233 | vm.instructionPointer = quad.Result.(int) - 1
234 | return nil
235 | }
236 |
237 | func (vm *VirtualMachine) executeGotoF(quad shared.Quadruple) error {
238 | condValue, err := vm.memoryManager.Load(quad.LeftOp.(int))
239 | if err != nil {
240 | return err
241 | }
242 |
243 | if condValue == 0 {
244 | vm.instructionPointer = quad.Result.(int) - 1
245 | }
246 |
247 | return nil
248 | }
249 |
250 | func (vm *VirtualMachine) executeParam(quad shared.Quadruple) error {
251 | valueAddr := quad.LeftOp.(int)
252 |
253 | if err := vm.memoryManager.PopFunctionSegment(); err != nil {
254 | return err
255 | }
256 | currentFunction := vm.functionStack.Pop()
257 |
258 | value, err := vm.memoryManager.Load(valueAddr)
259 | if err != nil {
260 | return err
261 | }
262 |
263 | vm.functionStack.Push(currentFunction)
264 | function, exists := vm.Functions[currentFunction.(string)]
265 | if exists {
266 | vm.memoryManager.PushNewFunctionSegment(false, function.IntVarsCount, function.FloatVarsCount)
267 | } else {
268 | return fmt.Errorf("function does not exist")
269 | }
270 |
271 | index := quad.RightOp.(int)
272 | currParam := function.Parameters[index]
273 | currParamAddr := currParam.Address
274 | if err := vm.memoryManager.Store(currParamAddr, value); err != nil {
275 | return err
276 | }
277 |
278 | return nil
279 | }
280 |
281 | func (vm *VirtualMachine) executeEra(quad shared.Quadruple) error {
282 | functionName := quad.LeftOp.(string)
283 | vm.functionStack.Push(functionName)
284 | functionInfo, exists := vm.Functions[functionName]
285 | //fmt.Println("This is the functionInfo", functionInfo)
286 | //fmt.Println("These are the counts", functionInfo.IntVarsCount, functionInfo.FloatVarsCount)
287 | if exists {
288 | vm.memoryManager.PushNewFunctionSegment(false, functionInfo.IntVarsCount, functionInfo.FloatVarsCount)
289 | } else {
290 | return fmt.Errorf("function does not exist")
291 | }
292 | return nil
293 | }
294 |
295 | func (vm *VirtualMachine) executeEndproc(quad shared.Quadruple) error {
296 | vm.instructionPointer = vm.returnPointer.Pop().(int)
297 | vm.functionStack.Pop()
298 | if err := vm.memoryManager.PopFunctionSegment(); err != nil {
299 | return err
300 | }
301 | return nil
302 | }
303 |
304 | func (vm *VirtualMachine) executeGosub(quad shared.Quadruple) error {
305 | start := quad.Result
306 | vm.returnPointer.Push(vm.instructionPointer)
307 | vm.instructionPointer = start.(int) - 1
308 | return nil
309 | }
310 |
--------------------------------------------------------------------------------
/tests/pogo_parser_tests/conditionals.pogo:
--------------------------------------------------------------------------------
1 | program conditionals;
2 |
3 | var result : float;
4 | var x, y, z : int;
5 |
6 | begin
7 | // Comments work as well!!!!
8 | /*
9 | multiline comments also work!
10 | look!
11 | */
12 | x = 5;
13 | y = 7;
14 | z = 9;
15 |
16 | if (x < y) {
17 | print("it worked")
18 | }
19 |
20 | end
--------------------------------------------------------------------------------
/tests/pogo_parser_tests/pogoPatito.pogo:
--------------------------------------------------------------------------------
1 | program pablo;
2 |
3 | var x, a : int;
4 | var y, z : float;
5 |
6 | func patito() {
7 | if (5 > 7) {
8 | x = -5;
9 | z = 7 + (x + y);
10 | x = 9;
11 | }
12 | };
13 |
14 | func patito2(x : int) {
15 | if (5 > 7) {
16 | x = -5;
17 | z = 7 + (x + y);
18 | x = 9;
19 | }
20 | };
21 |
22 | begin
23 | x = 5;
24 | a = 8 + ((5 + 40) + 8);
25 | if (x > 6) {
26 | x = 5;
27 | z = 7 * 8.0;
28 | z = 7.0 / 8.0;
29 | }
30 | // Comments that should be ignored
31 | print("hola")
32 |
33 | while (8.0 > y) {
34 | x = x + 1;
35 | if (x > 67) {
36 | print("wow")
37 | } else {
38 | print("no wow", x)
39 | patito()
40 | x = x * 2;
41 | patito2(x)
42 | }
43 | }
44 | end
--------------------------------------------------------------------------------
/tests/pogo_parser_tests/pogoparser_test.go:
--------------------------------------------------------------------------------
1 | package pogo_parser_tests
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "pogo/src/lexer"
7 | "pogo/src/parser"
8 | "pogo/src/storer"
9 | "testing"
10 | )
11 |
12 | func TestParser(t *testing.T) {
13 | fmt.Println("Test Pogo Parser")
14 | inputFile := os.Args[len(os.Args)-1]
15 | //inputFile := "simple.pogo"
16 | input, err := os.ReadFile(inputFile)
17 |
18 | if err != nil {
19 | t.Fatalf("Error reading input: %v", err)
20 | }
21 |
22 | lex := lexer.NewLexer(input)
23 | p := parser.NewParser(lex)
24 |
25 | err = p.ParseProgram()
26 | if err != nil {
27 | fmt.Println("Parse error:", err)
28 | return
29 | }
30 |
31 | if err := storer.SaveCompiledData(p.CodeGenerator.Quads, p.SymbolTable, p.CodeGenerator.MemoryManager, "test.pbin"); err != nil {
32 | fmt.Println(err)
33 | return
34 | }
35 |
36 | vm, err := storer.LoadCompiledData("test.pbin")
37 | if err := vm.Execute(); err != nil {
38 | fmt.Println(err)
39 | return
40 | }
41 | }
42 |
43 | //func TestParserFibo(t *testing.T) {
44 | // fmt.Println("Test Pogo Parser")
45 | // inputFile := "fibo.pogo"
46 | // input, err := os.ReadFile(inputFile)
47 | //
48 | // if err != nil {
49 | // t.Fatalf("Error reading input: %v", err)
50 | // }
51 | //
52 | // lex := lexer.NewLexer(input)
53 | // p := parser.NewParser(lex)
54 | //
55 | // err = p.ParseProgram()
56 | // if err != nil {
57 | // fmt.Println("Parse error:", err)
58 | // return
59 | // } else {
60 | // fmt.Println("Input successfully parsed!")
61 | // }
62 | //
63 | // if err := storer.SaveCompiledData(p.CodeGenerator.Quads, p.SymbolTable, p.CodeGenerator.MemoryManager, "test.pbin"); err != nil {
64 | // fmt.Println(err)
65 | // return
66 | // }
67 | //
68 | // vm, err := storer.LoadCompiledData("test.pbin")
69 | // // fmt.Println(vm)
70 | // if err := vm.Execute(); err != nil {
71 | // fmt.Println(err)
72 | // return
73 | // }
74 | //
75 | //}
76 |
--------------------------------------------------------------------------------
/tests/pogo_parser_tests/simple.pogo:
--------------------------------------------------------------------------------
1 | program Factorial;
2 |
3 | var result : float;
4 | var x : int;
5 |
6 | begin
7 | // Comments work as well!!!!
8 | /*
9 | multiline comments also work!
10 | look!
11 | */
12 | result = 1;
13 | x = 5;
14 | while (x > 0) {
15 | result = result * x;
16 | x = x - 1;
17 | }
18 | print("This is the result", result)
19 | end
--------------------------------------------------------------------------------
/tests/scanner_test.go:
--------------------------------------------------------------------------------
1 | package tests
2 |
3 | import (
4 | "pogo/src/lexer"
5 | "pogo/src/token"
6 | "testing"
7 | )
8 |
9 | func TestTokenizer(t *testing.T) {
10 | type Test struct {
11 | expectedType token.Type
12 | expectedLiteral string
13 | }
14 |
15 | const input = `
16 | program pablillo;
17 | var testVar, testVar1 : int;
18 | var test_var : float;
19 |
20 | begin
21 | testVar = 5;
22 | testVar1 = 7;
23 | if (testVar > testVar1) {
24 | print(testVar);
25 | }
26 |
27 | while (testVar == testVar1) {
28 | testVar = testVar - 1;
29 | }
30 | end
31 | `
32 |
33 | tests := []Test{
34 | {token.TokMap.Type("kwdProgram"), "program"},
35 | {token.TokMap.Type("id"), "pablillo"},
36 | {token.TokMap.Type("terminator"), ";"},
37 | {token.TokMap.Type("kwdVars"), "var"},
38 | {token.TokMap.Type("id"), "testVar"},
39 | {token.TokMap.Type("repeatTerminator"), ","},
40 | {token.TokMap.Type("id"), "testVar1"},
41 | {token.TokMap.Type("typeAssignOp"), ":"},
42 | {token.TokMap.Type("type"), "int"},
43 | {token.TokMap.Type("terminator"), ";"},
44 | {token.TokMap.Type("kwdVars"), "var"},
45 | {token.TokMap.Type("id"), "test_var"},
46 | {token.TokMap.Type("typeAssignOp"), ":"},
47 | {token.TokMap.Type("type"), "float"},
48 | {token.TokMap.Type("terminator"), ";"},
49 | {token.TokMap.Type("kwdBegin"), "begin"},
50 | {token.TokMap.Type("id"), "testVar"},
51 | {token.TokMap.Type("assignOp"), "="},
52 | {token.TokMap.Type("intLit"), "5"},
53 | {token.TokMap.Type("terminator"), ";"},
54 | {token.TokMap.Type("id"), "testVar1"},
55 | {token.TokMap.Type("assignOp"), "="},
56 | {token.TokMap.Type("intLit"), "7"},
57 | {token.TokMap.Type("terminator"), ";"},
58 | {token.TokMap.Type("kwdIf"), "if"},
59 | {token.TokMap.Type("openParan"), "("},
60 | {token.TokMap.Type("id"), "testVar"},
61 | {token.TokMap.Type("relOp"), ">"},
62 | {token.TokMap.Type("id"), "testVar1"},
63 | {token.TokMap.Type("closeParan"), ")"},
64 | {token.TokMap.Type("openBrace"), "{"},
65 | {token.TokMap.Type("kwdPrint"), "print"},
66 | {token.TokMap.Type("openParan"), "("},
67 | {token.TokMap.Type("id"), "testVar"},
68 | {token.TokMap.Type("closeParan"), ")"},
69 | {token.TokMap.Type("terminator"), ";"},
70 | {token.TokMap.Type("closeBrace"), "}"},
71 | {token.TokMap.Type("kwdWhile"), "while"},
72 | {token.TokMap.Type("openParan"), "("},
73 | {token.TokMap.Type("id"), "testVar"},
74 | {token.TokMap.Type("relOp"), "=="},
75 | {token.TokMap.Type("id"), "testVar1"},
76 | {token.TokMap.Type("closeParan"), ")"},
77 | {token.TokMap.Type("openBrace"), "{"},
78 | {token.TokMap.Type("id"), "testVar"},
79 | {token.TokMap.Type("assignOp"), "="},
80 | {token.TokMap.Type("id"), "testVar"},
81 | {token.TokMap.Type("expressionOp"), "-"},
82 | {token.TokMap.Type("intLit"), "1"},
83 | {token.TokMap.Type("terminator"), ";"},
84 | {token.TokMap.Type("closeBrace"), "}"},
85 | {token.TokMap.Type("kwdEnd"), "end"},
86 | }
87 |
88 | l := lexer.NewLexer([]byte(input))
89 |
90 | for i, tt := range tests {
91 | tok := l.Scan()
92 |
93 | if tok.Type != tt.expectedType {
94 | t.Fatalf("tests[%d] - tokentype wrong. expected='%s', got='%s' at line %d, column %d", i, token.TokMap.Id(tt.expectedType), token.TokMap.Id(tok.Type), tok.Pos.Line, tok.Pos.Column)
95 | }
96 |
97 | if string(tok.Lit) != tt.expectedLiteral {
98 | t.Fatalf("tests[%d] - literal wrong. expected='%q', got='%q' at line %d, column %d",
99 | i, tt.expectedLiteral, string(tok.Lit), tok.Pos.Line, tok.Pos.Column)
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------