mirror of
https://github.com/Fluffy-Bean/GoLox.git
synced 2024-12-26 17:16:04 +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"
|
||||
)
|
||||
|
||||
var hasError = false
|
||||
|
||||
func main() {
|
||||
if len(os.Args) > 2 {
|
||||
fmt.Println("Usage: lox [script]")
|
||||
|
@ -25,13 +27,15 @@ func parseFile(path string) {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
scanner := NewScanner()
|
||||
scanner.Parse(string(file))
|
||||
run(string(file))
|
||||
|
||||
if hasError {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func parsePrompt() {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
scanner := NewScanner()
|
||||
|
||||
for {
|
||||
fmt.Print("> ")
|
||||
|
@ -42,6 +46,27 @@ func parsePrompt() {
|
|||
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
|
||||
}
|
||||
|
|
154
scanner.go
154
scanner.go
|
@ -1,21 +1,157 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Scanner struct {
|
||||
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
|
||||
}
|
||||
|
||||
func (s *Scanner) Parse(source string) {
|
||||
fmt.Println(source)
|
||||
func (s *Scanner) scanToken() {
|
||||
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 {
|
||||
return &Scanner{}
|
||||
func (s *Scanner) advance() string {
|
||||
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
|
||||
|
||||
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 {
|
||||
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