-
-
Notifications
You must be signed in to change notification settings - Fork 27
/
token.go
142 lines (124 loc) · 2.7 KB
/
token.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
// Package token contains the tokens we understand when it comes
// to parsing our BASIC input.
package token
import (
"fmt"
"strings"
)
// Type is a string
type Type string
// Token contains a single token.
type Token struct {
// Type holds the type of the token
Type Type
// Literal holds the literal value.
Literal string
}
// pre-defined token-types
const (
// Core
EOF = "EOF" // End of file
NEWLINE = "NEWLINE" // Newlines are kept in our lexer-stream
LINENO = "LINENO" // Line-number of each input.
// Types
IDENT = "IDENT" // Identifier (i.e. variable name)
INT = "INT" // integer literal
STRING = "STRING" // string literal
BUILTIN = "BUILTIN" // builtin-function
// Implemented keywords.
END = "END"
GOSUB = "GOSUB"
GOTO = "GOTO"
INPUT = "INPUT"
LET = "LET"
REM = "REM"
RETURN = "RETURN"
// Did I mention that for-loops work? :D
FOR = "FOR"
NEXT = "NEXT"
STEP = "STEP"
TO = "TO"
// And conditionals?
IF = "IF"
THEN = "THEN"
ELSE = "ELSE"
// Binary operators
AND = "AND"
OR = "OR"
XOR = "XOR"
// Misc
DEF = "DEF"
DIM = "DIM"
FN = "FN"
READ = "READ"
SWAP = "SWAP"
DATA = "DATA"
// Woo-operators
ASSIGN = "=" // LET x = 3
ASTERISK = "*" // integer multiplication
COMMA = "," // PRINT 3, 54
MINUS = "-" // integer subtraction
MOD = "%" // integer modulus
PLUS = "+" // integer addition
SLASH = "/" // integer division
POW = "^" // power
COLON = ":"
SEMICOLON = ";"
LBRACKET = "("
RBRACKET = ")"
LINDEX = "["
RINDEX = "]"
// Comparison functions.
GT = ">"
GTEQUALS = ">="
LT = "<"
LTEQUALS = "<="
NOTEQUALS = "<>"
)
// reversed keywords
var keywords = map[string]Type{
"and": AND,
"data": DATA,
"dim": DIM,
"def": DEF,
"else": ELSE,
"end": END,
"fn": FN,
"for": FOR,
"gosub": GOSUB,
"goto": GOTO,
"if": IF,
"input": INPUT,
"let": LET,
"next": NEXT,
"or": OR,
"read": READ,
"rem": REM,
"return": RETURN,
"step": STEP,
"swap": SWAP,
"then": THEN,
"to": TO,
"xor": XOR,
}
// LookupIdentifier used to determine whether identifier is keyword nor not.
// We handle both upper-case and lower-cased keywords, for example both
// "print" and "PRINT" are considered identical.
func LookupIdentifier(identifier string) Type {
id := strings.ToLower(identifier)
if tok, ok := keywords[id]; ok {
return tok
}
return IDENT
}
// String creates a string-representation of a token
func (t Token) String() string {
//
// Special-case newline-token doesn't need an embedded newline.
//
lit := t.Literal
if t.Type == NEWLINE {
lit = "\\n"
}
return (fmt.Sprintf("Token{Type:%s Value:%s}", t.Type, lit))
}