Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
|
|
@ -0,0 +1,674 @@
|
|||
// Input: command line argument of file to process or console input. A two or
|
||||
// three character console input of digits followed by a new line will be
|
||||
// checked for an integer between zero and twenty-five to select a fixed test
|
||||
// case to run. Any other console input will be parsed.
|
||||
|
||||
// Code based on the Java version found here:
|
||||
// https://rosettacode.org/mw/index.php?title=Compiler/lexical_analyzer&action=edit§ion=22
|
||||
|
||||
// Class to halt the parsing with an exception.
|
||||
class ParsingFailed(message: String): Exception(message)
|
||||
|
||||
// Enumerate class of tokens supported by this scanner.
|
||||
enum class TokenType {
|
||||
Tk_End_of_input, Op_multiply, Op_divide, Op_mod, Op_add, Op_subtract,
|
||||
Op_negate, Op_not, Op_less, Op_lessequal, Op_greater, Op_greaterequal,
|
||||
Op_equal, Op_notequal, Op_assign, Op_and, Op_or, Kw_if,
|
||||
Kw_else, Kw_while, Kw_print, Kw_putc, Sy_LeftParen, Sy_RightParen,
|
||||
Sy_LeftBrace, Sy_RightBrace, Sy_Semicolon, Sy_Comma, Tk_Identifier,
|
||||
Tk_Integer, Tk_String;
|
||||
|
||||
override fun toString() =
|
||||
listOf("End_of_input", "Op_multiply", "Op_divide", "Op_mod", "Op_add",
|
||||
"Op_subtract", "Op_negate", "Op_not", "Op_less", "Op_lessequal",
|
||||
"Op_greater", "Op_greaterequal", "Op_equal", "Op_notequal",
|
||||
"Op_assign", "Op_and", "Op_or", "Keyword_if", "Keyword_else",
|
||||
"Keyword_while", "Keyword_print", "Keyword_putc", "LeftParen",
|
||||
"RightParen", "LeftBrace", "RightBrace", "Semicolon", "Comma",
|
||||
"Identifier", "Integer", "String")[this.ordinal]
|
||||
} // TokenType
|
||||
|
||||
// Data class of tokens returned by the scanner.
|
||||
data class Token(val token: TokenType, val value: String, val line: Int,
|
||||
val pos: Int) {
|
||||
|
||||
// Overridden method to display the token.
|
||||
override fun toString() =
|
||||
"%5d %5d %-15s %s".format(line, pos, this.token,
|
||||
when (this.token) {
|
||||
TokenType.Tk_Integer, TokenType.Tk_Identifier ->
|
||||
" %s".format(this.value)
|
||||
TokenType.Tk_String ->
|
||||
this.value.toList().joinToString("", " \"", "\"") {
|
||||
when (it) {
|
||||
'\t' ->
|
||||
"\\t"
|
||||
'\n' ->
|
||||
"\\n"
|
||||
'\u000b' ->
|
||||
"\\v"
|
||||
'\u000c' ->
|
||||
"\\f"
|
||||
'\r' ->
|
||||
"\\r"
|
||||
'"' ->
|
||||
"\\\""
|
||||
'\\' ->
|
||||
"\\"
|
||||
in ' '..'~' ->
|
||||
"$it"
|
||||
else ->
|
||||
"\\u%04x".format(it.code) } }
|
||||
else ->
|
||||
"" } )
|
||||
} // Token
|
||||
|
||||
// Function to display an error message and halt the scanner.
|
||||
fun error(line: Int, pos: Int, msg: String): Nothing =
|
||||
throw ParsingFailed("(%d, %d) %s\n".format(line, pos, msg))
|
||||
|
||||
// Class to process the source into tokens with properties of the
|
||||
// source string, the line number, the column position, the index
|
||||
// within the source string, the current character being processed,
|
||||
// and map of the keyword strings to the corresponding token type.
|
||||
class Lexer(private val s: String) {
|
||||
private var line = 1
|
||||
private var pos = 1
|
||||
private var position = 0
|
||||
private var chr =
|
||||
if (s.isEmpty())
|
||||
' '
|
||||
else
|
||||
s[0]
|
||||
private val keywords = mapOf<String, TokenType>(
|
||||
"if" to TokenType.Kw_if,
|
||||
"else" to TokenType.Kw_else,
|
||||
"print" to TokenType.Kw_print,
|
||||
"putc" to TokenType.Kw_putc,
|
||||
"while" to TokenType.Kw_while)
|
||||
|
||||
// Method to retrive the next character from the source. Use null after
|
||||
// the end of our source.
|
||||
private fun getNextChar() =
|
||||
if (++this.position >= this.s.length) {
|
||||
this.pos++
|
||||
this.chr = '\u0000'
|
||||
this.chr
|
||||
} else {
|
||||
this.pos++
|
||||
this.chr = this.s[this.position]
|
||||
when (this.chr) {
|
||||
'\n' -> {
|
||||
this.line++
|
||||
this.pos = 0
|
||||
} // line
|
||||
'\t' ->
|
||||
while (this.pos%8 != 1)
|
||||
this.pos++
|
||||
} // when
|
||||
this.chr
|
||||
} // if
|
||||
|
||||
// Method to return the division token, skip the comment, or handle the
|
||||
// error.
|
||||
private fun div_or_comment(line: Int, pos: Int): Token =
|
||||
if (getNextChar() != '*')
|
||||
Token(TokenType.Op_divide, "", line, pos);
|
||||
else {
|
||||
getNextChar() // Skip comment start
|
||||
outer@
|
||||
while (true)
|
||||
when (this.chr) {
|
||||
'\u0000' ->
|
||||
error(line, pos, "Lexer: EOF in comment");
|
||||
'*' ->
|
||||
if (getNextChar() == '/') {
|
||||
getNextChar() // Skip comment end
|
||||
break@outer
|
||||
} // if
|
||||
else ->
|
||||
getNextChar()
|
||||
} // when
|
||||
getToken()
|
||||
} // if
|
||||
|
||||
// Method to verify a character literal. Return the token or handle the
|
||||
// error.
|
||||
private fun char_lit(line: Int, pos: Int): Token {
|
||||
var c = getNextChar() // skip opening quote
|
||||
when (c) {
|
||||
'\'' ->
|
||||
error(line, pos, "Lexer: Empty character constant");
|
||||
'\\' ->
|
||||
c = when (getNextChar()) {
|
||||
'n' ->
|
||||
10.toChar()
|
||||
'\\' ->
|
||||
'\\'
|
||||
'\'' ->
|
||||
'\''
|
||||
else ->
|
||||
error(line, pos, "Lexer: Unknown escape sequence '\\%c'".
|
||||
format(this.chr)) }
|
||||
} // when
|
||||
if (getNextChar() != '\'')
|
||||
error(line, pos, "Lexer: Multi-character constant")
|
||||
getNextChar() // Skip closing quote
|
||||
return Token(TokenType.Tk_Integer, c.code.toString(), line, pos)
|
||||
} // char_lit
|
||||
|
||||
// Method to check next character to see whether it belongs to the token
|
||||
// we might be in the middle of. Return the correct token or handle the
|
||||
// error.
|
||||
private fun follow(expect: Char, ifyes: TokenType, ifno: TokenType,
|
||||
line: Int, pos: Int): Token =
|
||||
when {
|
||||
getNextChar() == expect -> {
|
||||
getNextChar()
|
||||
Token(ifyes, "", line, pos)
|
||||
} // matches
|
||||
ifno == TokenType.Tk_End_of_input ->
|
||||
error(line, pos,
|
||||
"Lexer: %c expected: (%d) '%c'".format(expect,
|
||||
this.chr.code, this.chr))
|
||||
else ->
|
||||
Token(ifno, "", line, pos)
|
||||
} // when
|
||||
|
||||
// Method to verify a character string. Return the token or handle the
|
||||
// error.
|
||||
private fun string_lit(start: Char, line: Int, pos: Int): Token {
|
||||
var result = ""
|
||||
while (getNextChar() != start)
|
||||
when (this.chr) {
|
||||
'\u0000' ->
|
||||
error(line, pos, "Lexer: EOF while scanning string literal")
|
||||
'\n' ->
|
||||
error(line, pos, "Lexer: EOL while scanning string literal")
|
||||
'\\' ->
|
||||
when (getNextChar()) {
|
||||
'\\' ->
|
||||
result += '\\'
|
||||
'n' ->
|
||||
result += '\n'
|
||||
'"' ->
|
||||
result += '"'
|
||||
else ->
|
||||
error(line, pos, "Lexer: Escape sequence unknown '\\%c'".
|
||||
format(this.chr))
|
||||
} // when
|
||||
else ->
|
||||
result += this.chr
|
||||
} // when
|
||||
getNextChar() // Toss closing quote
|
||||
return Token(TokenType.Tk_String, result, line, pos)
|
||||
} // string_lit
|
||||
|
||||
// Method to retrive an identifier or integer. Return the keyword
|
||||
// token, if the string matches one. Return the integer token,
|
||||
// if the string is all digits. Return the identifer token, if the
|
||||
// string is valid. Otherwise, handle the error.
|
||||
private fun identifier_or_integer(line: Int, pos: Int): Token {
|
||||
var is_number = true
|
||||
var text = ""
|
||||
while (this.chr in listOf('_')+('0'..'9')+('a'..'z')+('A'..'Z')) {
|
||||
text += this.chr
|
||||
is_number = is_number && this.chr in '0'..'9'
|
||||
getNextChar()
|
||||
} // while
|
||||
if (text.isEmpty())
|
||||
error(line, pos, "Lexer: Unrecognized character: (%d) %c".
|
||||
format(this.chr.code, this.chr))
|
||||
return when {
|
||||
text[0] in '0'..'9' ->
|
||||
if (!is_number)
|
||||
error(line, pos, "Lexer: Invalid number: %s".
|
||||
format(text))
|
||||
else {
|
||||
val max = Int.MAX_VALUE.toString()
|
||||
if (text.length > max.length || (text.length == max.length &&
|
||||
max < text))
|
||||
error(line, pos,
|
||||
"Lexer: Number exceeds maximum value %s".
|
||||
format(text))
|
||||
Token(TokenType.Tk_Integer, text, line, pos)
|
||||
} // if
|
||||
this.keywords.containsKey(text) ->
|
||||
Token(this.keywords[text]!!, "", line, pos)
|
||||
else ->
|
||||
Token(TokenType.Tk_Identifier, text, line, pos) }
|
||||
} // identifier_or_integer
|
||||
|
||||
// Method to skip whitespace both C's and Unicode ones and retrive the next
|
||||
// token.
|
||||
private fun getToken(): Token {
|
||||
while (this.chr in listOf('\t', '\n', '\u000b', '\u000c', '\r', ' ') ||
|
||||
this.chr.isWhitespace())
|
||||
getNextChar()
|
||||
val line = this.line
|
||||
val pos = this.pos
|
||||
return when (this.chr) {
|
||||
'\u0000' ->
|
||||
Token(TokenType.Tk_End_of_input, "", line, pos)
|
||||
'/' ->
|
||||
div_or_comment(line, pos)
|
||||
'\'' ->
|
||||
char_lit(line, pos)
|
||||
'<' ->
|
||||
follow('=', TokenType.Op_lessequal, TokenType.Op_less, line, pos)
|
||||
'>' ->
|
||||
follow('=', TokenType.Op_greaterequal, TokenType.Op_greater, line, pos)
|
||||
'=' ->
|
||||
follow('=', TokenType.Op_equal, TokenType.Op_assign, line, pos)
|
||||
'!' ->
|
||||
follow('=', TokenType.Op_notequal, TokenType.Op_not, line, pos)
|
||||
'&' ->
|
||||
follow('&', TokenType.Op_and, TokenType.Tk_End_of_input, line, pos)
|
||||
'|' ->
|
||||
follow('|', TokenType.Op_or, TokenType.Tk_End_of_input, line, pos)
|
||||
'"' ->
|
||||
string_lit(this.chr, line, pos)
|
||||
'{' -> {
|
||||
getNextChar()
|
||||
Token(TokenType.Sy_LeftBrace, "", line, pos)
|
||||
} // open brace
|
||||
'}' -> {
|
||||
getNextChar()
|
||||
Token(TokenType.Sy_RightBrace, "", line, pos)
|
||||
} // close brace
|
||||
'(' -> {
|
||||
getNextChar()
|
||||
Token(TokenType.Sy_LeftParen, "", line, pos)
|
||||
} // open paren
|
||||
')' -> {
|
||||
getNextChar()
|
||||
Token(TokenType.Sy_RightParen, "", line, pos)
|
||||
} // close paren
|
||||
'+' -> {
|
||||
getNextChar()
|
||||
Token(TokenType.Op_add, "", line, pos)
|
||||
} // plus
|
||||
'-' -> {
|
||||
getNextChar()
|
||||
Token(TokenType.Op_subtract, "", line, pos)
|
||||
} // dash
|
||||
'*' -> {
|
||||
getNextChar()
|
||||
Token(TokenType.Op_multiply, "", line, pos)
|
||||
} // asterisk
|
||||
'%' -> {
|
||||
getNextChar()
|
||||
Token(TokenType.Op_mod, "", line, pos)
|
||||
} // percent
|
||||
';' -> {
|
||||
getNextChar()
|
||||
Token(TokenType.Sy_Semicolon, "", line, pos)
|
||||
} // semicolon
|
||||
',' -> {
|
||||
getNextChar()
|
||||
Token(TokenType.Sy_Comma, "", line, pos)
|
||||
} // comma
|
||||
else ->
|
||||
identifier_or_integer(line, pos) }
|
||||
} // getToken
|
||||
|
||||
// Method to parse and display tokens.
|
||||
fun printTokens() {
|
||||
do {
|
||||
val t: Token = getToken()
|
||||
println(t)
|
||||
} while (t.token != TokenType.Tk_End_of_input)
|
||||
} // printTokens
|
||||
} // Lexer
|
||||
|
||||
|
||||
// Function to test all good tests from the website and produce all of the
|
||||
// error messages this program supports.
|
||||
fun tests(number: Int) {
|
||||
|
||||
// Function to generate test case 0 source: Hello World/Text.
|
||||
fun hello() {
|
||||
Lexer(
|
||||
"""/*
|
||||
Hello world
|
||||
*/
|
||||
print("Hello, World!\n");
|
||||
""").printTokens()
|
||||
} // hello
|
||||
|
||||
// Function to generate test case 1 source: Phoenix Number.
|
||||
fun phoenix() {
|
||||
Lexer(
|
||||
"""/*
|
||||
Show Ident and Integers
|
||||
*/
|
||||
phoenix_number = 142857;
|
||||
print(phoenix_number, "\n");""").printTokens()
|
||||
} // phoenix
|
||||
|
||||
// Function to generate test case 2 source: All Symbols.
|
||||
fun symbols() {
|
||||
Lexer(
|
||||
"""/*
|
||||
All lexical tokens - not syntactically correct, but that will
|
||||
have to wait until syntax analysis
|
||||
*/
|
||||
/* Print */ print /* Sub */ -
|
||||
/* Putc */ putc /* Lss */ <
|
||||
/* If */ if /* Gtr */ >
|
||||
/* Else */ else /* Leq */ <=
|
||||
/* While */ while /* Geq */ >=
|
||||
/* Lbrace */ { /* Eq */ ==
|
||||
/* Rbrace */ } /* Neq */ !=
|
||||
/* Lparen */ ( /* And */ &&
|
||||
/* Rparen */ ) /* Or */ ||
|
||||
/* Uminus */ - /* Semi */ ;
|
||||
/* Not */ ! /* Comma */ ,
|
||||
/* Mul */ * /* Assign */ =
|
||||
/* Div */ / /* Integer */ 42
|
||||
/* Mod */ % /* String */ "String literal"
|
||||
/* Add */ + /* Ident */ variable_name
|
||||
/* character literal */ '\n'
|
||||
/* character literal */ '\\'
|
||||
/* character literal */ ' '""").printTokens()
|
||||
} // symbols
|
||||
|
||||
// Function to generate test case 3 source: Test Case 4.
|
||||
fun four() {
|
||||
Lexer(
|
||||
"""/*** test printing, embedded \n and comments with lots of '*' ***/
|
||||
print(42);
|
||||
print("\nHello World\nGood Bye\nok\n");
|
||||
print("Print a slash n - \\n.\n");""").printTokens()
|
||||
} // four
|
||||
|
||||
// Function to generate test case 4 source: Count.
|
||||
fun count() {
|
||||
Lexer(
|
||||
"""count = 1;
|
||||
while (count < 10) {
|
||||
print("count is: ", count, "\n");
|
||||
count = count + 1;
|
||||
}""").printTokens()
|
||||
} // count
|
||||
|
||||
// Function to generate test case 5 source: 100 Doors.
|
||||
fun doors() {
|
||||
Lexer(
|
||||
"""/* 100 Doors */
|
||||
i = 1;
|
||||
while (i * i <= 100) {
|
||||
print("door ", i * i, " is open\n");
|
||||
i = i + 1;
|
||||
}""").printTokens()
|
||||
} // doors
|
||||
|
||||
// Function to generate test case 6 source: Negative Tests.
|
||||
fun negative() {
|
||||
Lexer(
|
||||
"""a = (-1 * ((-1 * (5 * 15)) / 10));
|
||||
print(a, "\n");
|
||||
b = -a;
|
||||
print(b, "\n");
|
||||
print(-b, "\n");
|
||||
print(-(1), "\n");""").printTokens()
|
||||
} // negative
|
||||
|
||||
// Function to generate test case 7 source: Deep.
|
||||
fun deep() {
|
||||
Lexer(
|
||||
"""print(---------------------------------+++5, "\n");
|
||||
print(((((((((3 + 2) * ((((((2))))))))))))), "\n");
|
||||
|
||||
if (1) { if (1) { if (1) { if (1) { if (1) { print(15, "\n"); } } } } }""").printTokens()
|
||||
} // deep
|
||||
|
||||
// Function to generate test case 8 source: Greatest Common Divisor.
|
||||
fun gcd() {
|
||||
Lexer(
|
||||
"""/* Compute the gcd of 1071, 1029: 21 */
|
||||
|
||||
a = 1071;
|
||||
b = 1029;
|
||||
|
||||
while (b != 0) {
|
||||
new_a = b;
|
||||
b = a % b;
|
||||
a = new_a;
|
||||
}
|
||||
print(a);""").printTokens()
|
||||
} // gcd
|
||||
|
||||
// Function to generate test case 9 source: Factorial.
|
||||
fun factorial() {
|
||||
Lexer(
|
||||
"""/* 12 factorial is 479001600 */
|
||||
|
||||
n = 12;
|
||||
result = 1;
|
||||
i = 1;
|
||||
while (i <= n) {
|
||||
result = result * i;
|
||||
i = i + 1;
|
||||
}
|
||||
print(result);""").printTokens()
|
||||
} // factorial
|
||||
|
||||
// Function to generate test case 10 source: Fibonacci Sequence.
|
||||
fun fibonacci() {
|
||||
Lexer(
|
||||
"""/* fibonacci of 44 is 701408733 */
|
||||
|
||||
n = 44;
|
||||
i = 1;
|
||||
a = 0;
|
||||
b = 1;
|
||||
while (i < n) {
|
||||
w = a + b;
|
||||
a = b;
|
||||
b = w;
|
||||
i = i + 1;
|
||||
}
|
||||
print(w, "\n");""").printTokens()
|
||||
} // fibonacci
|
||||
|
||||
// Function to generate test case 11 source: FizzBuzz.
|
||||
fun fizzbuzz() {
|
||||
Lexer(
|
||||
"""/* FizzBuzz */
|
||||
i = 1;
|
||||
while (i <= 100) {
|
||||
if (!(i % 15))
|
||||
print("FizzBuzz");
|
||||
else if (!(i % 3))
|
||||
print("Fizz");
|
||||
else if (!(i % 5))
|
||||
print("Buzz");
|
||||
else
|
||||
print(i);
|
||||
|
||||
print("\n");
|
||||
i = i + 1;
|
||||
}""").printTokens()
|
||||
} // fizzbuzz
|
||||
|
||||
// Function to generate test case 12 source: 99 Bottles of Beer.
|
||||
fun bottles() {
|
||||
Lexer(
|
||||
"""/* 99 bottles */
|
||||
bottles = 99;
|
||||
while (bottles > 0) {
|
||||
print(bottles, " bottles of beer on the wall\n");
|
||||
print(bottles, " bottles of beer\n");
|
||||
print("Take one down, pass it around\n");
|
||||
bottles = bottles - 1;
|
||||
print(bottles, " bottles of beer on the wall\n\n");
|
||||
}""").printTokens()
|
||||
} // bottles
|
||||
|
||||
// Function to generate test case 13 source: Primes.
|
||||
fun primes() {
|
||||
Lexer(
|
||||
"""/*
|
||||
Simple prime number generator
|
||||
*/
|
||||
count = 1;
|
||||
n = 1;
|
||||
limit = 100;
|
||||
while (n < limit) {
|
||||
k=3;
|
||||
p=1;
|
||||
n=n+2;
|
||||
while ((k*k<=n) && (p)) {
|
||||
p=n/k*k!=n;
|
||||
k=k+2;
|
||||
}
|
||||
if (p) {
|
||||
print(n, " is prime\n");
|
||||
count = count + 1;
|
||||
}
|
||||
}
|
||||
print("Total primes found: ", count, "\n");""").printTokens()
|
||||
} // primes
|
||||
|
||||
// Function to generate test case 14 source: Ascii Mandelbrot.
|
||||
fun ascii() {
|
||||
Lexer(
|
||||
"""{
|
||||
/*
|
||||
This is an integer ascii Mandelbrot generator
|
||||
*/
|
||||
left_edge = -420;
|
||||
right_edge = 300;
|
||||
top_edge = 300;
|
||||
bottom_edge = -300;
|
||||
x_step = 7;
|
||||
y_step = 15;
|
||||
|
||||
max_iter = 200;
|
||||
|
||||
y0 = top_edge;
|
||||
while (y0 > bottom_edge) {
|
||||
x0 = left_edge;
|
||||
while (x0 < right_edge) {
|
||||
y = 0;
|
||||
x = 0;
|
||||
the_char = ' ';
|
||||
i = 0;
|
||||
while (i < max_iter) {
|
||||
x_x = (x * x) / 200;
|
||||
y_y = (y * y) / 200;
|
||||
if (x_x + y_y > 800 ) {
|
||||
the_char = '0' + i;
|
||||
if (i > 9) {
|
||||
the_char = '@';
|
||||
}
|
||||
i = max_iter;
|
||||
}
|
||||
y = x * y / 100 + y0;
|
||||
x = x_x - y_y + x0;
|
||||
i = i + 1;
|
||||
}
|
||||
putc(the_char);
|
||||
x0 = x0 + x_step;
|
||||
}
|
||||
putc('\n');
|
||||
y0 = y0 - y_step;
|
||||
}
|
||||
}
|
||||
""").printTokens()
|
||||
} // ascii
|
||||
|
||||
when (number) {
|
||||
0 ->
|
||||
hello()
|
||||
1 ->
|
||||
phoenix()
|
||||
2 ->
|
||||
symbols()
|
||||
3 ->
|
||||
four()
|
||||
4 ->
|
||||
count()
|
||||
5 ->
|
||||
doors()
|
||||
6 ->
|
||||
negative()
|
||||
7 ->
|
||||
deep()
|
||||
8 ->
|
||||
gcd()
|
||||
9 ->
|
||||
factorial()
|
||||
10 ->
|
||||
fibonacci()
|
||||
11 ->
|
||||
fizzbuzz()
|
||||
12 ->
|
||||
bottles()
|
||||
13 ->
|
||||
primes()
|
||||
14 ->
|
||||
ascii()
|
||||
15 -> // Lexer: Empty character constant
|
||||
Lexer("''").printTokens()
|
||||
16 -> // Lexer: Unknown escape sequence
|
||||
Lexer("'\\x").printTokens()
|
||||
17 -> // Lexer: Multi-character constant
|
||||
Lexer("' ").printTokens()
|
||||
18 -> // Lexer: EOF in comment
|
||||
Lexer("/*").printTokens()
|
||||
19 -> // Lexer: EOL in string
|
||||
Lexer("\"\n").printTokens()
|
||||
20 -> // Lexer: EOF in string
|
||||
Lexer("\"").printTokens()
|
||||
21 -> // Lexer: Escape sequence unknown
|
||||
Lexer("\"\\x").printTokens()
|
||||
22 -> // Lexer: Unrecognized character
|
||||
Lexer("~").printTokens()
|
||||
23 -> // Lexer: invalid number
|
||||
Lexer("9a9").printTokens()
|
||||
24 -> // Lexer: Number exceeds maximum value
|
||||
Lexer("2147483648\n9223372036854775808").printTokens()
|
||||
25 -> // Lexer: Operator expected
|
||||
Lexer("|.").printTokens()
|
||||
else ->
|
||||
println("Invalid test number %d!".format(number))
|
||||
} // when
|
||||
} // tests
|
||||
|
||||
// Main function to check our source and read its data before parsing it.
|
||||
// With no source specified, run the test of all symbols.
|
||||
fun main(args: Array<String>) {
|
||||
try {
|
||||
val s =
|
||||
if (args.size > 0 && args[0].isNotEmpty()) // file on command line
|
||||
java.util.Scanner(java.io.File(args[0]))
|
||||
else // use the console
|
||||
java.util.Scanner(System.`in`)
|
||||
var source = ""
|
||||
while (s.hasNext())
|
||||
source += s.nextLine()+
|
||||
if (s.hasNext())
|
||||
"\n"
|
||||
else
|
||||
""
|
||||
if (args.size > 0 && args[0].isNotEmpty()) // file on command line
|
||||
Lexer(source).printTokens()
|
||||
else {
|
||||
val digits = source.filter { it in '0'..'9' }
|
||||
when {
|
||||
source.isEmpty() -> // nothing given
|
||||
tests(2)
|
||||
source.length in 1..2 && digits.length == source.length &&
|
||||
digits.toInt() in 0..25 ->
|
||||
tests(digits.toInt())
|
||||
else ->
|
||||
Lexer(source).printTokens()
|
||||
} // when
|
||||
} // if
|
||||
} catch(e: Throwable) {
|
||||
println(e.message)
|
||||
System.exit(1)
|
||||
} // try
|
||||
} // main
|
||||
Loading…
Add table
Add a link
Reference in a new issue