├── .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 | logo 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 | --------------------------------------------------------------------------------