-
Notifications
You must be signed in to change notification settings - Fork 0
/
wacc.go
167 lines (135 loc) · 3.75 KB
/
wacc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
package main
// WACC Group 34
//
// wacc.go: Main program
//
// Handles the input file(s)
// Handles flag(s) parsing
// Handles exit codes in case Syntax/Semantic errors are encountered
import (
"bufio"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
)
const (
exitSyntax = 100
exitSemantic = 200
)
// parseInput checks the syntax of the input file and exits if there
// are any errors
func parseInput(filename string) *WACC {
// Open the input wacc file and read the code
file, err := os.Open(filename)
buffer, err := ioutil.ReadAll(file)
if err != nil {
log.Print(err)
os.Exit(exitSyntax)
}
// Initialise the Lexer and Parser
wacc := &WACC{Buffer: string(buffer), File: filename}
wacc.Init()
// Parse the supplied code and check for errors
err = wacc.Parse()
if err != nil {
log.Print(err)
os.Exit(exitSyntax)
}
return wacc
}
// generateASTFromWACC takes the wacc file and the included files and generates
// the AST
func generateASTFromWACC(wacc *WACC, ifm *IncludeFiles) *AST {
// Parse the library generated tree and return the sanitized AST
ast, err := ParseAST(wacc, ifm)
if err != nil {
fmt.Println(err.Error())
os.Exit(exitSyntax)
}
// Look for further syntax errors, which were missed by the grammar
if retErrs := ast.CheckFunctionCodePaths(); len(retErrs) > 0 {
for _, err := range retErrs {
fmt.Println(err.Error())
}
os.Exit(exitSyntax)
}
return ast
}
// semanticAnalysis checks the semantics of the imput file and exits if there
// any errors
func semanticAnalysis(ast *AST) {
// Check the semantics of the syntactically correct program
if typeErrs := ast.TypeCheck(); len(typeErrs) > 0 {
for _, err := range typeErrs {
fmt.Println(err.Error())
}
os.Exit(exitSemantic)
}
}
// optimisation optimises the AST by modifying and replacing nodes to make
// the expression simpler
func optimise(ast *AST) {
ast.Optimise()
}
// codeGeneration generates the assembly code for the input file and puts it in
// a `.s` file
func codeGeneration(ast *AST, flags *Flags) {
// Initialise Code Generation
armFile := bufio.NewWriter(os.Stdout)
// Put the assembly code in a file, if assembly flag missing
if !flags.printAssembly {
armFileHandle, err := os.Create(flags.assemblyfile)
if err != nil {
log.Fatal(err)
}
defer armFileHandle.Close()
armFile = bufio.NewWriter(armFileHandle)
}
// If the noassembly flag is not set
// Take all the instructions in the channel and push them to the defined
// IO Writer
if !flags.noassembly {
for instr := range ast.CodeGen() {
fInstr := fmt.Sprintf("%v\n", instr)
fmt.Fprint(armFile, fInstr)
}
}
// Flush the buffered writer
armFile.Flush()
}
// main is the starting point of the compiler
func main() {
// Parse all the supplied arguments
var flags = &Flags{}
flags.Parse()
// Prints compiler stage, if verbose flag is supplied
flags.Start()
// Get the directory of the base file
dir := filepath.Dir(flags.filename)
// Create a new instace of the IncludeFiles struct
ifm := &IncludeFiles{dir: dir}
ifm.Include(flags.filename)
// Initial syntax analysis by the lexer/parser library
wacc := parseInput(flags.filename)
// Prints the PEG Tree structure, if peg flag is supplied
if flags.printPEGTree {
fmt.Println("-- Printing PEG Tree")
wacc.PrintSyntaxTree()
}
// Generate AST from the WACC struct produced by the peg library
ast := generateASTFromWACC(wacc, ifm)
// Perform semantic analysis on the AST
semanticAnalysis(ast)
if flags.optimise {
// Perform optimisation on the AST
optimise(ast)
}
// Prints the AST in pretty format, if appropriate flag supplied
flags.PrintPrettyAST(ast)
// Generate assembly code for the input wacc file
codeGeneration(ast, flags)
// Prints compiler stage, if verbose flag is supplied
flags.Finish()
}