mirror of
https://github.com/Noratrieb/GRSBPL.git
synced 2026-01-14 19:55:03 +01:00
Add files via upload
This commit is contained in:
parent
99b5e92e1c
commit
8a4ccb8b2b
7 changed files with 718 additions and 0 deletions
92
StackBasedLanguage/README.md
Normal file
92
StackBasedLanguage/README.md
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
# GRSBPL - Generic Random Stack Based Programming Language
|
||||||
|
|
||||||
|
uses some form of reverse polish notation
|
||||||
|
|
||||||
|
```
|
||||||
|
1 5 * 5 +
|
||||||
|
> 10
|
||||||
|
```
|
||||||
|
|
||||||
|
There is a stack and variables. Operations are done on the stack, and you can store results in variables (a bit like in
|
||||||
|
the JVM). The stack contains integer values. Floating point numbers are not supported.
|
||||||
|
|
||||||
|
When the program finishes (run to the end of the program), the last value on the stack is returned. If the stack is
|
||||||
|
clear, 0 is always returned. If there is an error during execution, -1 is returned along with an error message to
|
||||||
|
stderr.
|
||||||
|
|
||||||
|
## Operators and keywords:
|
||||||
|
|
||||||
|
* any number `n` -> push the numeric value of n
|
||||||
|
* any character `'c'` -> push c as its escaped ascii value
|
||||||
|
* `+` -> add two values on the stack, pops both and pushes the result
|
||||||
|
* `-` -> subtract two values on the stack, pops both and pushes the result
|
||||||
|
* `*` -> multiply two values on the stack, pops both and pushes the result
|
||||||
|
* `/` -> divide, pops both and pushes the result
|
||||||
|
* `%` -> mod, pops both and pushes the result
|
||||||
|
* `not` -> invert stack value (!=0 -> 0, 0 -> 1)
|
||||||
|
* `swap` -> swaps the 2 top stack values
|
||||||
|
* `out` -> pop and output it to the console as ascii
|
||||||
|
* `nount` -> pop and output as a number to the console
|
||||||
|
* `in` -> push input char as ascii to the stack
|
||||||
|
* `# comment #` text between # is ignored
|
||||||
|
* `# comment\n` text after # is ignored
|
||||||
|
* `&word` -> pop and store it in a variable
|
||||||
|
* `@word` -> load variable and push it, does not consume the variable
|
||||||
|
* `:indent` -> define a label
|
||||||
|
* `goto ident` -> goto a label if the value on the stack is !=0, peek
|
||||||
|
|
||||||
|
Identifier: \w
|
||||||
|
|
||||||
|
Character escape sequences:
|
||||||
|
\n, \r, \\, \0, \', \b, \f
|
||||||
|
|
||||||
|
## Examples:
|
||||||
|
|
||||||
|
FizzBuzz
|
||||||
|
|
||||||
|
```grsbpl
|
||||||
|
1 &i # init loop counter
|
||||||
|
:start # set start label
|
||||||
|
@i 100 - not goto exit # if i is 100, exit
|
||||||
|
@i 15 % not goto print_fizz_buzz # fizzbuzz
|
||||||
|
@i 5 % not goto print_buzz # buzz
|
||||||
|
@i 3 % not goto print_fizz # fizz
|
||||||
|
@i nout '\n' out # normal number
|
||||||
|
:end # go back here after printing
|
||||||
|
@i 1 + &i # increment i
|
||||||
|
1 goto start # go back to the start
|
||||||
|
|
||||||
|
:print_fizz_buzz
|
||||||
|
'F' out 'i' out 'z' out 'z' out 'B' out 'u' out 'z' out 'z' out '\n' out
|
||||||
|
goto end
|
||||||
|
:print_fizz
|
||||||
|
'F' out 'i' out 'z' out 'z' out '\n' out
|
||||||
|
goto end
|
||||||
|
:print_buzz
|
||||||
|
'B' out 'u' out 'z' out 'z' out '\n' out
|
||||||
|
goto end
|
||||||
|
|
||||||
|
:exit 0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Some Tips
|
||||||
|
|
||||||
|
* Increment a variable:
|
||||||
|
`@i 1 + &i`
|
||||||
|
* Pop a value from the stack and discard it:
|
||||||
|
`&dev_null` (just use any unused variable)
|
||||||
|
* Goto if equal
|
||||||
|
`@i 100 - not goto finished`
|
||||||
|
* Goto not equal
|
||||||
|
`@i 100 - goto finished`
|
||||||
|
* Exit the program
|
||||||
|
`... goto exit ... :exit 0`
|
||||||
|
* Exit with exit code depending on the branch
|
||||||
|
```grsbpl
|
||||||
|
...
|
||||||
|
69 swap goto exit # push 69 to the 2nd stack position
|
||||||
|
...
|
||||||
|
5 swap goto exit # push 5 to the 2nd stack position
|
||||||
|
...
|
||||||
|
:exit &del # pop the top stack value to expose the pushed value
|
||||||
|
```
|
||||||
30
StackBasedLanguage/pom.xml
Normal file
30
StackBasedLanguage/pom.xml
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.github.nilstrieb</groupId>
|
||||||
|
<artifactId>GRSBPL</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<version>5.6.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
<version>5.6.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>14</maven.compiler.source>
|
||||||
|
<maven.compiler.target>14</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</project>
|
||||||
63
StackBasedLanguage/src/main/java/IntStack.java
Normal file
63
StackBasedLanguage/src/main/java/IntStack.java
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
import java.util.OptionalInt;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
public class IntStack {
|
||||||
|
private int[] values;
|
||||||
|
private int pointer;
|
||||||
|
|
||||||
|
private static final int INITIAL_CAPACITY = 100;
|
||||||
|
|
||||||
|
public IntStack() {
|
||||||
|
this(INITIAL_CAPACITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntStack(int initialCapacity) {
|
||||||
|
values = new int[initialCapacity];
|
||||||
|
pointer = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void push(int value) {
|
||||||
|
checkResize();
|
||||||
|
values[++pointer] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int pop() {
|
||||||
|
if (pointer == -1) {
|
||||||
|
throw new IndexOutOfBoundsException("Cannot pop below zero");
|
||||||
|
}
|
||||||
|
return values[pointer--];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int peek() {
|
||||||
|
return values[pointer];
|
||||||
|
}
|
||||||
|
|
||||||
|
public OptionalInt tryPop() {
|
||||||
|
if (pointer == -1) {
|
||||||
|
return OptionalInt.empty();
|
||||||
|
} else {
|
||||||
|
return OptionalInt.of(pop());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void performOn2(BiFunction<Integer, Integer, Integer> function) {
|
||||||
|
int val2 = pop();
|
||||||
|
int val1 = pop();
|
||||||
|
push(function.apply(val1, val2));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkResize() {
|
||||||
|
if (pointer == values.length - 1) {
|
||||||
|
int[] newValues = new int[values.length * 2];
|
||||||
|
System.arraycopy(values, 0, newValues, 0, values.length);
|
||||||
|
this.values = newValues;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void swap() {
|
||||||
|
int val1 = pop();
|
||||||
|
int val2 = pop();
|
||||||
|
push(val1);
|
||||||
|
push(val2);
|
||||||
|
}
|
||||||
|
}
|
||||||
295
StackBasedLanguage/src/main/java/Interpreter.java
Normal file
295
StackBasedLanguage/src/main/java/Interpreter.java
Normal file
|
|
@ -0,0 +1,295 @@
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Interpreter {
|
||||||
|
|
||||||
|
private final Map<String, Runnable> KEYWORDS = Map.of(
|
||||||
|
"out", this::out,
|
||||||
|
"nout", this::nout,
|
||||||
|
"in", this::in,
|
||||||
|
"goto", this::condGoto,
|
||||||
|
"not", this::not,
|
||||||
|
"swap", this::swap
|
||||||
|
);
|
||||||
|
|
||||||
|
private IntStack stack;
|
||||||
|
private HashMap<String, Integer> variables;
|
||||||
|
private HashMap<String, Integer> labels;
|
||||||
|
private char[] program;
|
||||||
|
private int i;
|
||||||
|
private int lineNumber;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
if (args.length < 2) {
|
||||||
|
System.err.println("usage: <filename>");
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String s = Files.readString(Path.of(args[1]));
|
||||||
|
Interpreter interpreter = new Interpreter();
|
||||||
|
int exit = interpreter.run(s.toCharArray());
|
||||||
|
System.exit(exit);
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("File not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int run(char[] chars) {
|
||||||
|
program = chars;
|
||||||
|
stack = new IntStack();
|
||||||
|
variables = new HashMap<>();
|
||||||
|
labels = new HashMap<>();
|
||||||
|
i = 0;
|
||||||
|
lineNumber = 1;
|
||||||
|
|
||||||
|
firstPass();
|
||||||
|
i = 0;
|
||||||
|
lineNumber = 1;
|
||||||
|
|
||||||
|
while (hasNext()) {
|
||||||
|
try {
|
||||||
|
runStatement();
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("Exception occurred on line: " + lineNumber);
|
||||||
|
e.printStackTrace();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rest();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int rest() {
|
||||||
|
OptionalInt i = stack.tryPop();
|
||||||
|
|
||||||
|
if (i.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return i.getAsInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void firstPass() {
|
||||||
|
while (hasNext()) {
|
||||||
|
if (advance() == ':') {
|
||||||
|
label();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runStatement() {
|
||||||
|
switch (advance()) {
|
||||||
|
case '+' -> add();
|
||||||
|
case '-' -> subtract();
|
||||||
|
case '*' -> multiply();
|
||||||
|
case '/' -> divide();
|
||||||
|
case '%' -> modulo();
|
||||||
|
case '\'' -> character();
|
||||||
|
case '\n' -> lineNumber++;
|
||||||
|
case ' ', '\t', '\r' -> {
|
||||||
|
}
|
||||||
|
case '#' -> comment();
|
||||||
|
case '&' -> store();
|
||||||
|
case '@' -> load();
|
||||||
|
case ':' -> ignoreLabel();
|
||||||
|
default -> {
|
||||||
|
if (Character.isDigit(current())) {
|
||||||
|
number();
|
||||||
|
} else {
|
||||||
|
keyword();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void add() {
|
||||||
|
stack.performOn2(Integer::sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void subtract() {
|
||||||
|
stack.performOn2((i1, i2) -> i1 - i2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void multiply() {
|
||||||
|
stack.performOn2((i1, i2) -> i1 * i2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void divide() {
|
||||||
|
stack.performOn2((i1, i2) -> i1 / i2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void modulo() {
|
||||||
|
stack.performOn2((i1, i2) -> i1 % i2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void character() {
|
||||||
|
int value = advance();
|
||||||
|
if (value == '\\') {
|
||||||
|
char escaped = advance();
|
||||||
|
value = switch (escaped) {
|
||||||
|
case 'n' -> '\n';
|
||||||
|
case 'r' -> '\r';
|
||||||
|
case '\\' -> '\\';
|
||||||
|
case '0' -> '\0';
|
||||||
|
case '\'' -> '\'';
|
||||||
|
case 'b' -> '\b';
|
||||||
|
case 'f' -> '\f';
|
||||||
|
default -> {
|
||||||
|
System.err.println("Invalid escape sequence: \\" + escaped + " on line " + lineNumber);
|
||||||
|
System.exit(1);
|
||||||
|
throw new IllegalStateException("system exit failed");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
stack.push(value);
|
||||||
|
consume();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void comment() {
|
||||||
|
while (true) {
|
||||||
|
char next = advance();
|
||||||
|
if (next == '\n') {
|
||||||
|
lineNumber++;
|
||||||
|
break;
|
||||||
|
} else if (next == '#') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void store() {
|
||||||
|
whitespace();
|
||||||
|
String name = ident();
|
||||||
|
variables.put(name, stack.pop());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void load() {
|
||||||
|
whitespace();
|
||||||
|
String name = ident();
|
||||||
|
stack.push(variables.get(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void label() {
|
||||||
|
whitespace();
|
||||||
|
String name = ident();
|
||||||
|
labels.put(name, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume but don't use
|
||||||
|
private void ignoreLabel() {
|
||||||
|
whitespace();
|
||||||
|
ident();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void number() {
|
||||||
|
String number = String.valueOf(current());
|
||||||
|
while (Character.isDigit(peek())) {
|
||||||
|
number += advance();
|
||||||
|
}
|
||||||
|
stack.push(Integer.parseInt(number));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String ident() {
|
||||||
|
String word = String.valueOf(current());
|
||||||
|
|
||||||
|
while (Character.isAlphabetic(peek()) || Character.isDigit(peek()) || peek() == '_') {
|
||||||
|
word += advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void keyword() {
|
||||||
|
String word = ident();
|
||||||
|
|
||||||
|
Runnable r = KEYWORDS.get(word);
|
||||||
|
|
||||||
|
if (r == null) {
|
||||||
|
throw new RuntimeException("Invalid keyword: " + word);
|
||||||
|
}
|
||||||
|
r.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void whitespace() {
|
||||||
|
while (Character.isWhitespace(advance())) {
|
||||||
|
if (current() == '\n') {
|
||||||
|
lineNumber++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// keywords
|
||||||
|
private void out() {
|
||||||
|
System.out.print((char) stack.pop());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void nout() {
|
||||||
|
System.out.print(stack.pop());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void in() {
|
||||||
|
try {
|
||||||
|
stack.push(System.in.read());
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("Error reading input on line number " + lineNumber);
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void condGoto() {
|
||||||
|
whitespace();
|
||||||
|
String label = ident();
|
||||||
|
consume();
|
||||||
|
if (stack.peek() != 0) {
|
||||||
|
Integer index = labels.get(label);
|
||||||
|
if (index == null) {
|
||||||
|
System.err.println("Label :" + label + " not found on line number: " + lineNumber);
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
i = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void not() {
|
||||||
|
int value = stack.pop();
|
||||||
|
if (value == 0) {
|
||||||
|
stack.push(1);
|
||||||
|
} else {
|
||||||
|
stack.push(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void swap() {
|
||||||
|
stack.swap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// parsing
|
||||||
|
private char current() {
|
||||||
|
return program[i - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
private char advance() {
|
||||||
|
if (i == program.length) {
|
||||||
|
return '\0';
|
||||||
|
}
|
||||||
|
return program[i++];
|
||||||
|
}
|
||||||
|
|
||||||
|
private char peek() {
|
||||||
|
if (i == program.length) {
|
||||||
|
return '\0';
|
||||||
|
}
|
||||||
|
return program[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void consume() {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasNext() {
|
||||||
|
return i < program.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
41
StackBasedLanguage/src/test/java/IntStackTest.java
Normal file
41
StackBasedLanguage/src/test/java/IntStackTest.java
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class IntStackTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void pushPop() {
|
||||||
|
IntStack s = new IntStack();
|
||||||
|
|
||||||
|
s.push(100);
|
||||||
|
s.push(50);
|
||||||
|
|
||||||
|
assertEquals(50, s.pop());
|
||||||
|
assertEquals(100, s.pop());
|
||||||
|
|
||||||
|
assertThrows(IndexOutOfBoundsException.class, s::pop);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void applyFunction() {
|
||||||
|
IntStack s = new IntStack();
|
||||||
|
s.push(10);
|
||||||
|
s.push(2);
|
||||||
|
s.performOn2((i1, i2) -> i1 / i2);
|
||||||
|
assertEquals(5, s.pop());
|
||||||
|
assertThrows(IndexOutOfBoundsException.class, s::pop);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void resize() {
|
||||||
|
IntStack s = new IntStack();
|
||||||
|
for (int i = 0; i < 1000; i++) {
|
||||||
|
s.push(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 999; i >= 0; i--) {
|
||||||
|
assertEquals(i, s.pop());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
178
StackBasedLanguage/src/test/java/InterpreterTest.java
Normal file
178
StackBasedLanguage/src/test/java/InterpreterTest.java
Normal file
|
|
@ -0,0 +1,178 @@
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
class InterpreterTest {
|
||||||
|
|
||||||
|
static Interpreter interpreter;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setup() {
|
||||||
|
interpreter = new Interpreter();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void arithmeticOperations() {
|
||||||
|
String program = "1 1 * 2 +";
|
||||||
|
int result = 3;
|
||||||
|
assertEquals(result, interpreter.run(program.toCharArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void bigNumbers() {
|
||||||
|
String program = "1000 1234 +";
|
||||||
|
int result = 2234;
|
||||||
|
|
||||||
|
assertEquals(result, interpreter.run(program.toCharArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void comment() {
|
||||||
|
String program = "1 # sdkfjsaf se9 83 252h43ui\n 2 # test 5 # +";
|
||||||
|
int result = 3;
|
||||||
|
|
||||||
|
assertEquals(result, interpreter.run(program.toCharArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void variables() {
|
||||||
|
String program = "1 &one 2 &two 3 &three 8 @two +";
|
||||||
|
int result = 10;
|
||||||
|
assertEquals(result, interpreter.run(program.toCharArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void labels() {
|
||||||
|
String program = "1 :first 2 0";
|
||||||
|
int result = 0;
|
||||||
|
assertEquals(result, interpreter.run(program.toCharArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void gotoBack() {
|
||||||
|
String program = "10 &i \n" +
|
||||||
|
":start \n" +
|
||||||
|
"@i nout '\n' out \n" +
|
||||||
|
"@i 1 - &i \n" +
|
||||||
|
"@i goto start \n" +
|
||||||
|
" 0";
|
||||||
|
int result = 0;
|
||||||
|
assertEquals(result, interpreter.run(program.toCharArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void gotoSkip() {
|
||||||
|
String program = "1 :first 0 goto first 1 goto skip 3754 78349758 :skip";
|
||||||
|
int result = 1;
|
||||||
|
assertEquals(result, interpreter.run(program.toCharArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fizzBuzz() throws IOException, URISyntaxException {
|
||||||
|
String program = Files.readString(Path.of(getClass().getResource("fizzbuzz.grsbpl").toURI()));
|
||||||
|
int result = 0;
|
||||||
|
assertEquals(result, interpreter.run(program.toCharArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void stackManipulationTest() {
|
||||||
|
String program = "1 2 swap";
|
||||||
|
int result = 1;
|
||||||
|
assertEquals(result, interpreter.run(program.toCharArray()));
|
||||||
|
|
||||||
|
String program2 = "0 not";
|
||||||
|
int result2 = 1;
|
||||||
|
assertEquals(result2, interpreter.run(program2.toCharArray()));
|
||||||
|
|
||||||
|
String program3 = "1 not";
|
||||||
|
int result3 = 0;
|
||||||
|
assertEquals(result3, interpreter.run(program3.toCharArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void outTest() {
|
||||||
|
String program = "'\n' '!' 'd' 'l' 'r' 'o' 'w' ' ' 'o' 'l' 'l' 'e' 'h' out out out out out out out out out out out out out 0";
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
OutStream o = null;
|
||||||
|
try {
|
||||||
|
o = new OutStream();
|
||||||
|
System.setOut(o);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(result, interpreter.run(program.toCharArray()));
|
||||||
|
assertEquals("hello world!\n", o.getOut());
|
||||||
|
}
|
||||||
|
|
||||||
|
static class OutStream extends PrintStream {
|
||||||
|
private final StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
|
public OutStream() throws FileNotFoundException {
|
||||||
|
super(new OutputStream() {
|
||||||
|
@Override
|
||||||
|
public void write(int b) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void print(boolean b) {
|
||||||
|
builder.append(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void print(char c) {
|
||||||
|
builder.append(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void print(int i) {
|
||||||
|
builder.append(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void print(long l) {
|
||||||
|
builder.append(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void print(float f) {
|
||||||
|
builder.append(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void print(double d) {
|
||||||
|
builder.append(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void print(char[] s) {
|
||||||
|
builder.append(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void print(String s) {
|
||||||
|
builder.append(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void print(Object obj) {
|
||||||
|
super.print(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOut() {
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
StackBasedLanguage/src/test/resources/fizzbuzz.grsbpl
Normal file
19
StackBasedLanguage/src/test/resources/fizzbuzz.grsbpl
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
1 &i # init loop counter
|
||||||
|
:start # set start label
|
||||||
|
@i 100 - not goto finished # if i is 100, finish
|
||||||
|
@i 15 % not goto print_fizz_buzz # fizzbuzz
|
||||||
|
@i 5 % not goto print_buzz # buzz
|
||||||
|
@i 3 % not goto print_fizz # fizz
|
||||||
|
@i nout '\n' out # normal number
|
||||||
|
:end # go back here after printing
|
||||||
|
@i 1 + &i # increment i
|
||||||
|
1 goto start # go back to the start
|
||||||
|
|
||||||
|
:print_fizz_buzz
|
||||||
|
'F' out 'i' out 'z' out 'z' out 'B' out 'u' out 'z' out 'z' out '\n' out goto end
|
||||||
|
:print_fizz
|
||||||
|
'F' out 'i' out 'z' out 'z' out '\n' out goto end
|
||||||
|
:print_buzz
|
||||||
|
'B' out 'u' out 'z' out 'z' out '\n' out goto end
|
||||||
|
|
||||||
|
:finished 0
|
||||||
Loading…
Add table
Add a link
Reference in a new issue