A compiler and disassembler for the Graal Script 2 (GS2) language used in GraalOnline games.
- GS2 Compiler: Convert GS2 source code (
.gs2,.txt) to bytecode (.gs2bc) - GS2 Disassembler: Disassemble bytecode files to human-readable format
- Full AST-based compilation: Proper parsing and semantic analysis
- Multi-file support: Process multiple files or directories at once
- WASM support: Compile to WebAssembly for browser usage
Before building, clone the repository and recursively clone the submodules:
git clone https://github.com/vinvicta/gs2-parser.git --recursive
cd gs2-parser- CMake (3.10+)
- C++ Compiler (C++17 support required: GCC 7+, Clang 5+, MSVC 2017+)
- Bison (3.4+)
- Flex (2.6+)
sudo apt-get install cmake g++ bison flexbrew install cmake bison flexvcpkg install cmake bison flexmkdir build
cd build
cmake ..
make -j$(nproc)The executable will be created at ../bin/gs2test.
First, ensure you have Emscripten installed. Then:
mkdir build
cd build
emcmake cmake ..
make -j$(nproc)The resulting gs2test.js and gs2test.wasm files can be imported into a webpage.
Basic usage:
./bin/gs2test script.gs2
# Creates: script.gs2bcWith custom output:
./bin/gs2test script.gs2 -o output.gs2bcVerbose mode:
./bin/gs2test script.gs2 -vThe disassembler converts .gs2bc bytecode files to human-readable disassembly.
Basic disassembly:
./bin/gs2test script.gs2bc -d
# Creates: script.gs2With custom output:
./bin/gs2test script.gs2bc -d -o disassembled.gs2Verbose disassembly:
./bin/gs2test script.gs2bc -d -vGS2 Script Compiler/Disassembler
Usage:
gs2test [OPTIONS] INPUT [OUTPUT]
gs2test INPUT -o OUTPUT
gs2test --help
Arguments:
INPUT Input file (.gs2, .txt, or .gs2bc) or directory
OUTPUT Output file (.gs2bc for compile, .gs2 for disassemble)
Options:
-o, --output FILE Specify output file
-d, --disassemble Disassemble .gs2bc to .gs2 format
-v, --verbose Verbose output
-h, --help Show this help message
Examples:
gs2test script.gs2 # Creates script.gs2bc (compile)
gs2test script.gs2bc -d # Creates script.gs2 (disassemble)
gs2test script.gs2 output.gs2bc # Creates output.gs2bc
gs2test script.gs2bc -o output.gs2 -d # Creates output.gs2 (disassemble)
gs2test scripts/ # Process directory
gs2test file1.gs2 file2.gs2 file3.gs2 # Process multiple files
Process a directory:
./bin/gs2test scripts/Process multiple files:
./bin/gs2test file1.gs2 file2.gs2 file3.gs2The disassembler generates a human-readable disassembly showing:
- Function structure and names
- String constants from the string table
- Opcode names and descriptions
- Operands (numbers, strings, jump offsets)
Example output:
function onCreated() {
// Function: onCreated
// Opcodes: 52 bytes
// OP_SET_INDEX
// OP_TYPE_ARRAY
// OP_FUNC_PARAMS_END
// OP_JMP 2493
// OP_TYPE_VAR "x"
// OP_MEMBER_ACCESS
// OP_TYPE_NUMBER 5
// OP_ASSIGN
// OP_TEMP
// OP_TYPE_VAR "y"
// OP_MEMBER_ACCESS
// OP_TYPE_NUMBER 10
// OP_ASSIGN
// OP_TYPE_ARRAY
// OP_TYPE_STRING "Result: "
// OP_TEMP
// OP_TYPE_VAR "x"
// OP_MEMBER_ACCESS
// OP_CONV_TO_FLOAT
// OP_TEMP
// OP_TYPE_VAR "y"
// OP_MEMBER_ACCESS
// OP_CONV_TO_FLOAT
// OP_ADD
// OP_CONV_TO_STRING
// OP_JOIN
// OP_TYPE_VAR "echo"
// OP_CALL
// OP_INDEX_DEC
// OP_TRUE
// OP_RET
}
GS2 bytecode files (.gs2bc) consist of 4 segments:
-
GS1 Flags Segment (type 1)
- Bitflags for GS1 events
-
Function Table Segment (type 2)
- List of functions with their opcodes and names
- Format:
[opIndex: 4 bytes][functionName: null-terminated string]
-
String Table Segment (type 3)
- All string constants used in the script
- Format:
[string: null-terminated]
-
Bytecode Segment (type 4)
- The actual bytecode instructions
- Format:
[opcode: 1 byte][operands: variable]
Numbers are encoded with a prefix byte:
0xF0-F2: Signed integers (1, 2, 4 bytes)0xF3-F5: Numbers afterOP_TYPE_NUMBER(1, 2, 4 bytes)0xF6: Double-precision float (as null-terminated string)
The compiler uses a multi-stage pipeline:
- Lexical Analysis: Flex-based scanner tokenizes GS2 source
- Parsing: Bison-based parser builds Abstract Syntax Tree (AST)
- Semantic Analysis: Type checking and symbol resolution
- Code Generation: Visitor pattern emits bytecode
- Optimization: Jump label resolution and optimization
The disassembler performs bytecode analysis:
- Segment Parsing: Reads bytecode segments (flags, functions, strings, bytecode)
- Instruction Decoding: Parses opcodes and operands
- Symbol Resolution: Extracts string table and function names
- Disassembly Generation: Produces human-readable output
src/parser.y: Bison grammar for GS2 languagesrc/scanner.l: Flex lexer for tokenizationsrc/ast/: AST node definitionssrc/visitors/GS2CompilerVisitor.cpp: Bytecode emissionsrc/visitors/GS2Decompiler.cpp: Bytecode parsing and disassemblysrc/GS2Bytecode.cpp: Bytecode buffer managementsrc/opcodes.h: Opcode definitions and mappings
Run the test suite:
cd build
make run-testsGenerate test baselines:
make test-baselinesClean test artifacts:
make test-cleanThis project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
- Original compiler by xtjoeytx
- Disassembler implementation by vinvicta
- Based on the GraalOnline GS2 language specification