Chapter 2

Task 4.6
This commit is contained in:
Michał 2024-09-23 09:32:55 +01:00
parent 33a2ae4e47
commit 809a2c7b0d
5 changed files with 241 additions and 16 deletions

33
main.go
View file

@ -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
}

View file

@ -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,
}
}

View file

@ -1 +1,3 @@
print "Hello, World!";
// this is a comment
(( )){} // grouping stuff
!*+-/ =<> <= == // operators

1
scripts/helloworld.lox Normal file
View file

@ -0,0 +1 @@
print "Hello, World!";

View file

@ -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)
}