Skip to content

Commit b19d29b

Browse files
committed
scanning
0 parents  commit b19d29b

File tree

14 files changed

+412
-0
lines changed

14 files changed

+412
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Crafting Interpreter

lox/.idea/.gitignore

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lox/.idea/misc.xml

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lox/.idea/modules.xml

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lox/example/basic.lox

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
print "Hello, world!";
2+
3+
true;
4+
false;
5+
1234;
6+
12.34;
7+
8+
"I am a string";
9+
"";
10+
"123";
11+
12+
nil;
13+
14+
add + me;
15+
subtract - me;
16+
multiply * me;
17+
divide / me;
18+
19+
-negateMe;
20+
21+
less < than;
22+
lessThan <= orEqual;
23+
greater > than;
24+
greaterThan >= orEqual;
25+
26+
1 == 2;
27+
"cat" != "dog";
28+
29+
314 == "pi";
30+
123 == "123";
31+
32+
!true;
33+
!false;
34+
35+
true and false;
36+
true and true;
37+
false or false;
38+
true or false;
39+
40+
var average = (min + max) / 2;
41+
42+
{
43+
print "one statement.";
44+
print "two statements.";
45+
}
46+
47+
var a = "hello";
48+
var b;
49+
print a;
50+
51+
if (condition) {
52+
print "yes";
53+
} else {
54+
print "no";
55+
}
56+
57+
var a = 1;
58+
while (a < 10) {
59+
print a;
60+
a = a + 1;
61+
}
62+
63+
for (var a = 1; a < 10; a = a + 1) {
64+
print a;
65+
}
66+
67+
makeBreakfast(bacon, egg, toast);
68+
makeBreakfast();
69+
70+
fun printSum(a, b) {
71+
print a + b;
72+
}
73+
74+
fun returnSum(a, b) {
75+
return a + b;
76+
}
77+
78+
class Breakfast {
79+
80+
cook() { print "Eggs a-fryin'!"; }
81+
82+
serve(who) { print "Enjoy your breakfast, " + who + "."; }
83+
84+
}

lox/lox.iml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<module type="JAVA_MODULE" version="4">
3+
<component name="NewModuleRootManager" inherit-compiler-output="true">
4+
<exclude-output />
5+
<content url="file://$MODULE_DIR$">
6+
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
7+
</content>
8+
<orderEntry type="inheritedJdk" />
9+
<orderEntry type="sourceFolder" forTests="false" />
10+
</component>
11+
</module>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package com.craftinginterpreters.lox;
2+
3+
import java.io.BufferedReader;
4+
import java.io.IOException;
5+
import java.io.InputStreamReader;
6+
import java.nio.charset.Charset;
7+
import java.nio.file.Files;
8+
import java.nio.file.Paths;
9+
import java.util.List;
10+
11+
public class Lox {
12+
static boolean hadError = false;
13+
14+
public static void main(String[] args) throws IOException {
15+
if (args.length > 1) {
16+
System.out.println("Usage: jlox [script]");
17+
} else if (args.length == 1) {
18+
runFile(args[0]);
19+
} else {
20+
runPrompt();
21+
}
22+
}
23+
24+
private static void runFile(String path) throws IOException {
25+
byte[] bytes = Files.readAllBytes(Paths.get(path));
26+
run(new String(bytes, Charset.defaultCharset()));
27+
28+
if (hadError) System.exit(65);
29+
}
30+
31+
private static void runPrompt() throws IOException {
32+
InputStreamReader input = new InputStreamReader(System.in);
33+
BufferedReader reader = new BufferedReader(input);
34+
35+
for (;;) {
36+
System.out.print("> ");
37+
String line = reader.readLine();
38+
if (line == null) break;
39+
run(line);
40+
41+
hadError = false;
42+
}
43+
}
44+
45+
private static void run(String source) {
46+
Scanner scanner = new Scanner(source);
47+
List<Token> tokens = scanner.scanTokens();
48+
49+
for (Token token: tokens) {
50+
System.out.println(token);
51+
}
52+
}
53+
54+
static void error(int line, String message) {
55+
report(line, "", message);
56+
}
57+
58+
private static void report(int line, String where, String message) {
59+
System.err.println("[line " + line + "] Error" + where + ": " + message);
60+
hadError = true;
61+
}
62+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
package com.craftinginterpreters.lox;
2+
3+
import java.util.ArrayList;
4+
import java.util.HashMap;
5+
import java.util.List;
6+
import java.util.Map;
7+
8+
import static com.craftinginterpreters.lox.TokenType.*;
9+
10+
public class Scanner {
11+
private final String source;
12+
private int start = 0;
13+
private int current = 0;
14+
private int line = 1;
15+
private final List<Token> tokens = new ArrayList<>();
16+
17+
private static final Map<String, TokenType> keywords;
18+
19+
static {
20+
keywords = new HashMap<>();
21+
keywords.put("and", AND);
22+
keywords.put("class", CLASS);
23+
keywords.put("else", ELSE);
24+
keywords.put("false", FALSE);
25+
keywords.put("for", FOR);
26+
keywords.put("fun", FUN);
27+
keywords.put("if", IF);
28+
keywords.put("nil", NIL);
29+
keywords.put("or", OR);
30+
keywords.put("print", PRINT);
31+
keywords.put("return", RETURN);
32+
keywords.put("super", SUPER);
33+
keywords.put("this", THIS);
34+
keywords.put("true", TRUE);
35+
keywords.put("var", VAR);
36+
keywords.put("while", WHILE);
37+
}
38+
39+
Scanner(String source) {
40+
this.source = source;
41+
}
42+
43+
List<Token> scanTokens() {
44+
while (!isAtEnd()) {
45+
start = current;
46+
// [start, current)
47+
scanToken();
48+
}
49+
50+
tokens.add(new Token(EOF, "", null, line));
51+
return tokens;
52+
}
53+
54+
private void scanToken() {
55+
char c = advance();
56+
switch (c) {
57+
case '(': addToken(LEFT_PAREN); break;
58+
case ')': addToken(RIGHT_PAREN); break;
59+
case '{': addToken(LEFT_BRACE); break;
60+
case '}': addToken(RIGHT_BRACE); break;
61+
case ',': addToken(COMMA); break;
62+
case '.': addToken(DOT); break;
63+
case '-': addToken(MINUS); break;
64+
case '+': addToken(PLUS); break;
65+
case ';': addToken(SEMICOLON); break;
66+
case '*': addToken(STAR); break;
67+
case '!':
68+
addToken(match('=') ? BANG_EQUAL : BANG);
69+
break;
70+
case '=':
71+
addToken(match('=') ? EQUAL_EQUAL : EQUAL);
72+
break;
73+
case '<':
74+
addToken(match('=') ? LESS_EQUAL : LESS);
75+
break;
76+
case '>':
77+
addToken(match('=') ? GREATER_EQUAL : GREATER);
78+
break;
79+
case '/':
80+
if (match('/')) {
81+
// this is comment! until the end of this line
82+
while (peek() != '\n' && !isAtEnd()) advance();
83+
} else {
84+
addToken(SLASH);
85+
}
86+
break;
87+
88+
case '\n':
89+
line++;
90+
case ' ':
91+
case '\r':
92+
case '\t':
93+
break;
94+
95+
case '"': string(); break;
96+
97+
default:
98+
if (isDigit(c)) {
99+
number();
100+
} else if (isAlpha(c)) {
101+
identifier();
102+
} else {
103+
Lox.error(line, "Unexpected character.");
104+
}
105+
break;
106+
}
107+
}
108+
109+
private void identifier() {
110+
while (isAlphaNumeric(peek())) advance();
111+
112+
String text = source.substring(start, current);
113+
TokenType type = keywords.get(text);
114+
if (type == null) {
115+
addToken(IDENTIFIER);
116+
} else {
117+
addToken(type);
118+
}
119+
}
120+
121+
private static boolean isDigit(char c) {
122+
return c >= '0' && c <= '9';
123+
}
124+
125+
private static boolean isAlpha(char c) {
126+
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || (c == '_');
127+
}
128+
129+
private static boolean isAlphaNumeric(char c) {
130+
return isAlpha(c) || isDigit(c);
131+
}
132+
133+
private void number() {
134+
while (isDigit(peek())) {
135+
advance();
136+
}
137+
if (peek() == '.' && isDigit(peekNext())) {
138+
advance();
139+
while (isDigit(peek())) advance();
140+
}
141+
addToken(NUMBER, Double.parseDouble(source.substring(start, current)));
142+
}
143+
144+
private void string() {
145+
// continue until we find the closing "
146+
while (peek() != '"' && !isAtEnd()) {
147+
if (peek() == '\n') line++;
148+
advance();
149+
}
150+
151+
if (isAtEnd()) {
152+
Lox.error(line, "Unterminated string.");
153+
return;
154+
}
155+
advance();
156+
157+
String value = source.substring(start + 1, current - 1);
158+
addToken(STRING, value);
159+
}
160+
161+
private char peek() {
162+
// lookahead
163+
if (isAtEnd()) return '\0';
164+
return source.charAt(current);
165+
}
166+
167+
private char peekNext() {
168+
if (current + 1 >= source.length()) return '\0';
169+
return source.charAt(current + 1);
170+
}
171+
172+
private boolean match(char expected) {
173+
//
174+
if (isAtEnd()) return false;
175+
if (source.charAt(current) == expected) {
176+
current++;
177+
return true;
178+
}
179+
return false;
180+
}
181+
182+
private char advance() {
183+
current++;
184+
return source.charAt(current - 1);
185+
}
186+
187+
private void addToken(TokenType type) {
188+
addToken(type, null);
189+
}
190+
191+
private void addToken(TokenType type, Object literal) {
192+
String text = source.substring(start, current);
193+
tokens.add(new Token(type, text, literal, line));
194+
}
195+
196+
private boolean isAtEnd() {
197+
return current >= source.length();
198+
}
199+
}

0 commit comments

Comments
 (0)