mirror of
https://github.com/Fluffy-Bean/GoLox.git
synced 2024-12-27 01:16:05 +00:00
Chapter 2
Task 4.6
This commit is contained in:
parent
33a2ae4e47
commit
809a2c7b0d
33
main.go
33
main.go
|
@ -7,6 +7,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var hasError = false
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) > 2 {
|
if len(os.Args) > 2 {
|
||||||
fmt.Println("Usage: lox [script]")
|
fmt.Println("Usage: lox [script]")
|
||||||
|
@ -25,13 +27,15 @@ func parseFile(path string) {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
scanner := NewScanner()
|
run(string(file))
|
||||||
scanner.Parse(string(file))
|
|
||||||
|
if hasError {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parsePrompt() {
|
func parsePrompt() {
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
scanner := NewScanner()
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
fmt.Print("> ")
|
fmt.Print("> ")
|
||||||
|
@ -42,6 +46,27 @@ func parsePrompt() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
scanner.Parse(text)
|
run(text)
|
||||||
|
|
||||||
|
hasError = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func run(source string) {
|
||||||
|
scanner := NewScanner(source)
|
||||||
|
tokens := scanner.ScanTokens()
|
||||||
|
|
||||||
|
for _, token := range tokens {
|
||||||
|
fmt.Println(token.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fuck is just the error function, but collides with a builtin so whatever
|
||||||
|
func fuck(line int, msg string) {
|
||||||
|
report(line, "", msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func report(line int, where string, msg string) {
|
||||||
|
fmt.Printf("[line %d] Error %s: %s\n", line, where, msg)
|
||||||
|
hasError = true
|
||||||
|
}
|
||||||
|
|
156
scanner.go
156
scanner.go
|
@ -1,21 +1,157 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Scanner struct {
|
type Scanner struct {
|
||||||
tokens []Token
|
source string
|
||||||
|
tokens []Token
|
||||||
|
start int
|
||||||
|
current int
|
||||||
|
line int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scanner) GetTokens() []Token {
|
func (s *Scanner) ScanTokens() []Token {
|
||||||
|
for !s.isAtEnd() {
|
||||||
|
s.start = s.current
|
||||||
|
s.scanToken()
|
||||||
|
}
|
||||||
|
|
||||||
|
s.tokens = append(s.tokens, Token{
|
||||||
|
Type: EOF,
|
||||||
|
Lexeme: "",
|
||||||
|
Literal: "",
|
||||||
|
Line: s.line,
|
||||||
|
})
|
||||||
return s.tokens
|
return s.tokens
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scanner) Parse(source string) {
|
func (s *Scanner) scanToken() {
|
||||||
fmt.Println(source)
|
c := s.advance()
|
||||||
|
switch c {
|
||||||
|
case "(":
|
||||||
|
s.addToken(LeftBrace)
|
||||||
|
break
|
||||||
|
case ")":
|
||||||
|
s.addToken(RightBrace)
|
||||||
|
break
|
||||||
|
case "{":
|
||||||
|
s.addToken(LeftBrace)
|
||||||
|
break
|
||||||
|
case "}":
|
||||||
|
s.addToken(RightBrace)
|
||||||
|
break
|
||||||
|
case ",":
|
||||||
|
s.addToken(Comma)
|
||||||
|
break
|
||||||
|
case ".":
|
||||||
|
s.addToken(Dot)
|
||||||
|
break
|
||||||
|
case "-":
|
||||||
|
s.addToken(Minus)
|
||||||
|
break
|
||||||
|
case "+":
|
||||||
|
s.addToken(Plus)
|
||||||
|
break
|
||||||
|
case ";":
|
||||||
|
s.addToken(Semicolon)
|
||||||
|
break
|
||||||
|
case "*":
|
||||||
|
s.addToken(Star)
|
||||||
|
break
|
||||||
|
case "!":
|
||||||
|
if s.match("=") {
|
||||||
|
s.addToken(BangEqual)
|
||||||
|
} else {
|
||||||
|
s.addToken(Bang)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "=":
|
||||||
|
if s.match("=") {
|
||||||
|
s.addToken(EqualEqual)
|
||||||
|
} else {
|
||||||
|
s.addToken(Equal)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "<":
|
||||||
|
if s.match("=") {
|
||||||
|
s.addToken(LessEqual)
|
||||||
|
} else {
|
||||||
|
s.addToken(Less)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case ">":
|
||||||
|
if s.match("=") {
|
||||||
|
s.addToken(GreaterEqual)
|
||||||
|
} else {
|
||||||
|
s.addToken(Greater)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "/":
|
||||||
|
if s.match("/") {
|
||||||
|
for s.peek() != "\n" && !s.isAtEnd() {
|
||||||
|
s.advance()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s.addToken(Slash)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case " ":
|
||||||
|
case "\t":
|
||||||
|
case "\r":
|
||||||
|
// ignore whitespace
|
||||||
|
break
|
||||||
|
case "\n":
|
||||||
|
s.line += 1
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
fuck(s.line, "Unexpected Char.")
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewScanner() *Scanner {
|
func (s *Scanner) advance() string {
|
||||||
return &Scanner{}
|
c := string(s.source[s.current])
|
||||||
|
s.current += 1
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Scanner) peek() string {
|
||||||
|
if s.isAtEnd() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(s.source[s.current])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Scanner) match(expected string) bool {
|
||||||
|
if s.isAtEnd() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if string(s.source[s.current]) != expected {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
s.current += 1
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Scanner) addToken(token int) {
|
||||||
|
s.tokens = append(s.tokens, Token{
|
||||||
|
Type: token,
|
||||||
|
Lexeme: s.source[s.start:s.current],
|
||||||
|
Literal: "",
|
||||||
|
Line: s.line,
|
||||||
|
})
|
||||||
|
//fmt.Printf("[%d %d %d] ", s.line, s.current, s.start)
|
||||||
|
//fmt.Println(s.tokens[len(s.tokens)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Scanner) isAtEnd() bool {
|
||||||
|
return s.current >= len(s.source)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewScanner(source string) *Scanner {
|
||||||
|
return &Scanner{
|
||||||
|
source: source,
|
||||||
|
tokens: []Token{},
|
||||||
|
start: 0,
|
||||||
|
current: 0,
|
||||||
|
line: 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
print "Hello, World!";
|
// this is a comment
|
||||||
|
(( )){} // grouping stuff
|
||||||
|
!*+-/ =<> <= == // operators
|
||||||
|
|
1
scripts/helloworld.lox
Normal file
1
scripts/helloworld.lox
Normal file
|
@ -0,0 +1 @@
|
||||||
|
print "Hello, World!";
|
63
tokens.go
63
tokens.go
|
@ -1,5 +1,66 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Single Char tokens
|
||||||
|
LeftParen = iota
|
||||||
|
RightParen
|
||||||
|
LeftBrace
|
||||||
|
RightBrace
|
||||||
|
Comma
|
||||||
|
Dot
|
||||||
|
Minus
|
||||||
|
Plus
|
||||||
|
Semicolon
|
||||||
|
Slash
|
||||||
|
Star
|
||||||
|
|
||||||
|
// One or Two Char tokens
|
||||||
|
Bang
|
||||||
|
BangEqual
|
||||||
|
Equal
|
||||||
|
EqualEqual
|
||||||
|
Greater
|
||||||
|
GreaterEqual
|
||||||
|
Less
|
||||||
|
LessEqual
|
||||||
|
|
||||||
|
// Literals
|
||||||
|
Identifier
|
||||||
|
String
|
||||||
|
Number
|
||||||
|
|
||||||
|
// Keywords
|
||||||
|
And
|
||||||
|
Class
|
||||||
|
Else
|
||||||
|
False
|
||||||
|
Fun
|
||||||
|
For
|
||||||
|
If
|
||||||
|
Nah
|
||||||
|
Or
|
||||||
|
Print
|
||||||
|
Return
|
||||||
|
Super
|
||||||
|
This
|
||||||
|
True
|
||||||
|
Var
|
||||||
|
While
|
||||||
|
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
type Token struct {
|
type Token struct {
|
||||||
token string
|
Type int
|
||||||
|
Lexeme string
|
||||||
|
Literal string
|
||||||
|
Line int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Token) String() string {
|
||||||
|
return fmt.Sprintf("%d %s %s", t.Type, t.Lexeme, t.Literal)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue