-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
186 lines (149 loc) ยท 5.67 KB
/
main.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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package main
import (
"fmt"
"time"
"github.com/fatih/color"
codeGen "github.com/DanielNos/neco/codeGenerator"
"github.com/DanielNos/neco/errors"
"github.com/DanielNos/neco/lexer"
"github.com/DanielNos/neco/logger"
"github.com/DanielNos/neco/parser"
"github.com/DanielNos/neco/syntaxAnalyzer"
VM "github.com/DanielNos/neco/virtualMachine"
)
func printHelp() {
color.Set(color.Bold)
color.Set(color.FgHiYellow)
fmt.Println("Action Flags")
color.Set(color.Reset)
fmt.Println("build [target]")
fmt.Println(" -to --tokens Prints lexed tokens.")
fmt.Println(" -tr --tree Draws abstract syntax tree.")
fmt.Println(" -i --instructions Prints generated instructions.")
fmt.Println(" -d --dont-optimize Compiler won't optimize byte code.")
fmt.Println(" -s --silent Doesn't produce info messages when possible.")
fmt.Println(" -n --no-log Doesn't produce any log messages, even if there are errors.")
fmt.Println(" -l --log-level [LEVEL] Sets logging level. Possible values are 0 to 5 or level names.")
fmt.Println(" -o --out Sets output file path.")
fmt.Println(" -c --constants Prints constants stored in binary.")
fmt.Println("\nrun [target]")
fmt.Println("\nanalyze [target]")
fmt.Println(" -to --tokens Prints lexed tokens.")
fmt.Println(" -tr --tree Draws abstract syntax tree.")
fmt.Println(" -d --dontOptimize Compiler won't optimize byte code.")
}
func analyze(configuration *Configuration) (*parser.Node, *parser.Parser) {
action := "Analysis"
if configuration.Action == A_Build {
action = "Compilation"
}
// Tokenize
lexer := lexer.NewLexer(configuration.TargetPath)
tokens := lexer.Lex()
exitCode := 0
if lexer.ErrorCount != 0 {
logger.Error(fmt.Sprintf("Lexical analysis failed with %d error/s.", lexer.ErrorCount))
exitCode = errors.LEXICAL
} else {
logger.Success("Passed lexical analysis.")
}
// Analyze syntax
syntaxAnalyzer := syntaxAnalyzer.NewSyntaxAnalyzer(tokens, lexer.ErrorCount)
tokens = syntaxAnalyzer.Analyze()
if syntaxAnalyzer.ErrorCount != 0 {
logger.Error(fmt.Sprintf("Syntax analysis failed with %d error/s.", syntaxAnalyzer.ErrorCount))
// Print tokens
if configuration.PrintTokens {
logger.Info(fmt.Sprintf("Lexed %d tokens.", len(tokens)))
printTokens(tokens)
}
// Exit with correct return code
if exitCode == 0 {
logger.Fatal(errors.SYNTAX, fmt.Sprintf("๐ฟ %s failed with %d error/s.", action, lexer.ErrorCount+syntaxAnalyzer.ErrorCount))
} else {
logger.Fatal(exitCode, fmt.Sprintf("๐ฟ %s failed with %d error/s.", action, lexer.ErrorCount+syntaxAnalyzer.ErrorCount))
}
} else {
logger.Success("Passed syntax analysis.")
}
// Construct AST
p := parser.NewParser(tokens, syntaxAnalyzer.ErrorCount, configuration.Optimize)
tree := p.Parse()
// Print info
if p.ErrorCount != 0 {
logger.Error(fmt.Sprintf("Semantic analysis failed with %d error/s.", p.ErrorCount))
if exitCode == 0 {
exitCode = errors.SEMANTIC
}
} else {
logger.Success("Passed semantic analysis.")
}
// Print tokens
if configuration.PrintTokens {
printTokens(tokens)
}
// Visualize tree
if configuration.DrawTree {
if !configuration.PrintTokens {
fmt.Println()
}
parser.Visualize(tree)
fmt.Println()
}
if exitCode != 0 {
logger.Fatal(exitCode, fmt.Sprintf("๐ฟ %s failed with %d error/s.", action, lexer.ErrorCount+syntaxAnalyzer.ErrorCount+p.ErrorCount))
}
return tree, &p
}
func compile(configuration *Configuration) {
if !configuration.Optimize {
logger.Warning("Code optimization disabled.")
}
startTime := time.Now()
tree, p := analyze(configuration)
// Generate code
codeGenerator := codeGen.NewGenerator(tree, p.IntConstants, p.FloatConstants, p.StringConstants, configuration.Optimize)
codeGenerator.Generate()
// Print constants
if configuration.PrintConstants {
printConstants(len(p.StringConstants), len(p.IntConstants), len(p.FloatConstants), codeGenerator.Constants)
}
// Generation failed
if codeGenerator.ErrorCount != 0 {
logger.Fatal(errors.CODE_GENERATION, fmt.Sprintf("Failed code generation with %d error/s.", codeGenerator.ErrorCount))
}
logger.Info(fmt.Sprintf("Generated %d instructions.", len(codeGenerator.GlobalsInstructions)+len(codeGenerator.FunctionsInstructions)))
logger.Success(fmt.Sprintf("๐บ Compilation completed in %s.", time.Since(startTime)))
codeWriter := codeGen.NewCodeWriter(codeGenerator)
codeWriter.Write(configuration.OutputPath)
// Print generated instructions
if configuration.PrintInstructions {
printInstructions(&codeGenerator.GlobalsInstructions, codeGenerator.Constants)
printInstructions(&codeGenerator.FunctionsInstructions, codeGenerator.Constants)
fmt.Println()
}
}
func buildAndRun(configuration *Configuration) {
logger.Info("๐ฑ Compiling " + configuration.TargetPath)
compile(configuration)
virtualMachine := VM.NewVirtualMachine(configuration.OutputPath)
virtualMachine.Execute()
}
func main() {
configuration := processArguments()
switch configuration.Action {
case A_Build:
logger.Info("๐ฑ Compiling " + configuration.TargetPath)
compile(configuration)
case A_Run:
virtualMachine := VM.NewVirtualMachine(configuration.TargetPath)
virtualMachine.Execute()
case A_Analyze:
logger.Info("๐ฑ Analyzing " + configuration.TargetPath)
startTime := time.Now()
analyze(configuration)
logger.Success(fmt.Sprintf("๐บ Analyze completed in %s.", time.Since(startTime)))
case A_BuildAndRun:
buildAndRun(configuration)
}
}