parent
4576609b1e
commit
3867ef4991
@ -0,0 +1,160 @@
|
|||||||
|
# MinBasic guide
|
||||||
|
|
||||||
|
## Keywords and case sensitivity
|
||||||
|
|
||||||
|
Most things in MinBasic are described with keywords.
|
||||||
|
These keywords are *not* case-sensitive, meaning that `if x > 0 then` is equivalent to `IF x > 0 THEN`.
|
||||||
|
|
||||||
|
User-defined things, like functions and variables, *are case-sensitive*. So `myVariable`, `MYVARIABLE` and `myvariable` all refer to different things.
|
||||||
|
|
||||||
|
We recommend to prefer uppercase for keywords and lowercase for variable names.
|
||||||
|
|
||||||
|
## Comments
|
||||||
|
|
||||||
|
Comments are prefixed with the `REM` keyword.
|
||||||
|
|
||||||
|
## Variables and assignments
|
||||||
|
|
||||||
|
<!-- TODO: prevent usage of LET in incorrect places -->
|
||||||
|
|
||||||
|
To assign a value to a variable, use the `variable = value` syntax, where `value` can be any expression.
|
||||||
|
Optionally, you can prefix the assignment with the `LET` keyword.
|
||||||
|
|
||||||
|
To use a variable, simply put its name in an expression.
|
||||||
|
|
||||||
|
*Note: multi-line expressions are not yet supported.*
|
||||||
|
|
||||||
|
Variables don't need to be declared, and values can be assigned to them at any point in time.
|
||||||
|
Using a variable before it was assigned any value will yield `null` instead.
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```basic
|
||||||
|
REM Sets the variable "answer" to 42:
|
||||||
|
answer = 42
|
||||||
|
|
||||||
|
REM Also sets the variable "answer" to 42:
|
||||||
|
LET answer = 42
|
||||||
|
|
||||||
|
REM Sets the variable "x" to 21:
|
||||||
|
x = answer / 2
|
||||||
|
|
||||||
|
REM Increments "x" by one:
|
||||||
|
x = x + 1
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Expressions
|
||||||
|
|
||||||
|
The following binary operators are supported:
|
||||||
|
|
||||||
|
- Addition: `a + b`
|
||||||
|
- Subtraction: `a - b`
|
||||||
|
- Multiplication: `a * b`
|
||||||
|
- Division: `a / b`
|
||||||
|
- Modulo: `a % b`
|
||||||
|
- Less than: `a < b`
|
||||||
|
- Greater than: `a > b`
|
||||||
|
- Less than or equal: `a <= b`
|
||||||
|
- Greater than or equal: `a >= b`
|
||||||
|
- Equal: `a == b`
|
||||||
|
- Not equal: `a != b`
|
||||||
|
|
||||||
|
Multiplication and division have a greater precedence than addition and subtraction.
|
||||||
|
Comparisons have the lowest precedence.
|
||||||
|
You can wrap sub-expressions in parentheses to override precedence.
|
||||||
|
|
||||||
|
Some additional operators are only available by calling builtin functions, which are case-insensitive:
|
||||||
|
|
||||||
|
- Maximum: `MAX(a, b)`
|
||||||
|
- Minimum: `MIN(a, b)`
|
||||||
|
- Square root: `SQRT(a)`
|
||||||
|
- Floor: `FLOOR(a)`
|
||||||
|
- Ceil: `CEIL(a)`
|
||||||
|
- Round: `ROUND(a)`
|
||||||
|
- Rand: `RAND(a)`, generates a random number between `0` and `a`
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```basic
|
||||||
|
REM Picks a random integer between 0 and 63
|
||||||
|
n = FLOOR(RAND(64))
|
||||||
|
|
||||||
|
REM Sets x to the remainder of n by 8, and y by the integer part of n / 8
|
||||||
|
x = n % 8
|
||||||
|
y = FLOOR(n / 8)
|
||||||
|
|
||||||
|
REM Sets dist to the euclidean distance between (0, 0) and (x, y)
|
||||||
|
dist = SQRT(x * x + y * y)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Jumps and labels
|
||||||
|
|
||||||
|
Jumping allows you to interrupt the regular flow of instruction to go to another point in the program.
|
||||||
|
|
||||||
|
To perform a jump, you will first need to define where you want to jump to.
|
||||||
|
You have two options: prefixing a line with a number, or writing a named label.
|
||||||
|
|
||||||
|
Then, use the `GOTO` statement to jump to either a line number, or a label.
|
||||||
|
|
||||||
|
### Using line numbers
|
||||||
|
|
||||||
|
```basic
|
||||||
|
REM The following lines have been numbered. The numbers chosen are arbitrary, but they are commonly increasing multiples of 10,
|
||||||
|
REM which allows you to squeeze in debugging statements when needed.
|
||||||
|
10 PRINT "Hello, world"
|
||||||
|
20 PRINT "This is line 20"
|
||||||
|
|
||||||
|
REM We then jump back to line 20, which will cause an infinite loop printing "This is line 20"
|
||||||
|
30 GOTO 20
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using labels
|
||||||
|
|
||||||
|
```basic
|
||||||
|
REM We define here the "start" label
|
||||||
|
start:
|
||||||
|
PRINT "Hello, world"
|
||||||
|
|
||||||
|
REM We then jump to the "start" label, causing an infinite loop printing "Hello, world"
|
||||||
|
GOTO start
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conditions
|
||||||
|
|
||||||
|
The `IF` keyword allows you to execute different parts of the code depending on whether a condition is met or not.
|
||||||
|
The syntax for `IF` is as follows:
|
||||||
|
|
||||||
|
```basic
|
||||||
|
IF condition THEN
|
||||||
|
REM Code to be executed if "condition" is true
|
||||||
|
ELSE
|
||||||
|
REM Code to be executed if "condition" is false
|
||||||
|
END IF
|
||||||
|
```
|
||||||
|
|
||||||
|
If you do not need to execute code when the condition is false, then you can omit the `ELSE` keyword.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```basic
|
||||||
|
REM This is a condition without an ELSE block:
|
||||||
|
IF age < 0 THEN
|
||||||
|
PRINT "It seems like you weren't born yet..."
|
||||||
|
END IF
|
||||||
|
|
||||||
|
IF age < 18 THEN
|
||||||
|
PRINT "You are underaged"
|
||||||
|
ELSE
|
||||||
|
REM We can nest conditions within other conditions:
|
||||||
|
IF age == 18 THEN
|
||||||
|
PRINT "You just turned 18!"
|
||||||
|
ELSE
|
||||||
|
PRINT "You're over 18"
|
||||||
|
END IF
|
||||||
|
END IF
|
||||||
|
```
|
||||||
|
|
||||||
|
## Loops
|
||||||
|
|
||||||
|
<!-- TODO: finish implementing WHILE..WEND and DO..LOOP -->
|
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2023 Emilie BURGUN
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
@ -1,6 +1,37 @@
|
|||||||
# BASIC to Mindustry logic
|
# BASIC to Mindustry logic
|
||||||
|
|
||||||
This is a small transpiler from the [BASIC](https://en.wikipedia.org/wiki/BASIC) language to [Mindustry](https://github.com/Anuken/Mindustry/)'s [logic system](https://www.reddit.com/r/Mindustry/comments/kfea1e/an_overly_indepth_logic_guide/) (also known as `mlog`).
|
This is a small transpiler from a dialect of the [BASIC](https://en.wikipedia.org/wiki/BASIC) language, "MinBasic" (also known as `mbas`), to [Mindustry](https://github.com/Anuken/Mindustry/)'s [logic system](https://www.reddit.com/r/Mindustry/comments/kfea1e/an_overly_indepth_logic_guide/) (also known as `mlog`).
|
||||||
Basic is chosen as the source language as it already contains jumps (which mindustry heavily relies on), while allowing for some higher-order constructs like conditions, loops and functions.
|
Basic is chosen as the source language as it already contains jumps (which mindustry heavily relies on), while allowing for some higher-order constructs like conditions, loops and functions.
|
||||||
|
|
||||||
For now this is a heavily work-in-progress project.
|
## Installation and running
|
||||||
|
|
||||||
|
To use this project, start by cloning this git repository:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://git.shadamethyst.xyz/amethyst/basic-to-mindustry/
|
||||||
|
cd basic-to-mindustry
|
||||||
|
```
|
||||||
|
|
||||||
|
You will then need an installation of the Rust compiler, which you can quickly get from [rustup.rs](https://rustup.rs/).
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# To build the source code:
|
||||||
|
cargo build
|
||||||
|
|
||||||
|
# To run the binary:
|
||||||
|
./target/debug/basic-to-mindustry examples/prime.mbas
|
||||||
|
|
||||||
|
# You can do both of these with the following command (note the --):
|
||||||
|
cargo run -- examples/prime.mbas
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- TODO: add options -->
|
||||||
|
|
||||||
|
## VSCode syntax highlighting
|
||||||
|
|
||||||
|
Any language support extension for QuickBasic (the dialect MinBasic is based on) will work,
|
||||||
|
but if you would like an extension that was tailored to support MinBasic, you can have a look at [the one bundled with this project](./minbasic-vscode/README.md).
|
||||||
|
|
||||||
|
## Language features
|
||||||
|
|
||||||
|
The [GUIDE.md](./GUIDE.md) file describes how to write programs in MinBasic.
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
node_modules
|
||||||
|
*.vsix
|
||||||
|
.vscode
|
||||||
|
yarn.lock
|
||||||
|
target
|
@ -0,0 +1,7 @@
|
|||||||
|
.gitattributes
|
||||||
|
.gitignore
|
||||||
|
yarn.lock
|
||||||
|
node_modules
|
||||||
|
.vscode
|
||||||
|
*.vsix
|
||||||
|
target
|
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2023 Emilie BURGUN
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
@ -0,0 +1,22 @@
|
|||||||
|
# Language support for the MinBASIC language
|
||||||
|
|
||||||
|
This small vscode extension provides language support for the MinBASIC language.
|
||||||
|
|
||||||
|
To build it, run the following:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm i -g @vscode/vsce
|
||||||
|
vsce package
|
||||||
|
|
||||||
|
# Alternatively,
|
||||||
|
npx @vscode/vsce package
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, install it by running:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
vscodium --install-extension ./minbasic-vscode-*.vsix
|
||||||
|
|
||||||
|
# If you're using the proprietary builds of VSCode:
|
||||||
|
vscode --install-extension ./minbasic-vscode-*.vsix
|
||||||
|
```
|
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"comments": {
|
||||||
|
// symbol used for single line comment. Remove this entry if your language does not support line comments
|
||||||
|
"lineComment": "//",
|
||||||
|
// symbols used for start and end a block comment. Remove this entry if your language does not support block comments
|
||||||
|
"blockComment": [ "/*", "*/" ]
|
||||||
|
},
|
||||||
|
// symbols used as brackets
|
||||||
|
"brackets": [
|
||||||
|
["{", "}"],
|
||||||
|
["[", "]"],
|
||||||
|
["(", ")"]
|
||||||
|
],
|
||||||
|
// symbols that are auto closed when typing
|
||||||
|
"autoClosingPairs": [
|
||||||
|
["{", "}"],
|
||||||
|
["[", "]"],
|
||||||
|
["(", ")"],
|
||||||
|
["\"", "\""],
|
||||||
|
["'", "'"]
|
||||||
|
],
|
||||||
|
// symbols that can be used to surround a selection
|
||||||
|
"surroundingPairs": [
|
||||||
|
["{", "}"],
|
||||||
|
["[", "]"],
|
||||||
|
["(", ")"],
|
||||||
|
["\"", "\""],
|
||||||
|
["'", "'"]
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"name": "minbasic-vscode",
|
||||||
|
"displayName": "MinBasic Language Support",
|
||||||
|
"description": "Language support for the MinBasic language, which is an extension of QuickBasic for compilation to Mindustry Logic",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"engines": {
|
||||||
|
"vscode": "^1.79.0"
|
||||||
|
},
|
||||||
|
"categories": [
|
||||||
|
"Programming Languages"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.shadamethyst.xyz/amethyst/basic-to-mindustry"
|
||||||
|
},
|
||||||
|
"author": "Shad Amethyst",
|
||||||
|
"license": "MIT",
|
||||||
|
"contributes": {
|
||||||
|
"languages": [{
|
||||||
|
"id": "minbasic",
|
||||||
|
"aliases": ["MinBasic", "minbasic"],
|
||||||
|
"extensions": ["mbas"],
|
||||||
|
"configuration": "./language-configuration.json"
|
||||||
|
}],
|
||||||
|
"grammars": [{
|
||||||
|
"language": "minbasic",
|
||||||
|
"scopeName": "source.mbas",
|
||||||
|
"path": "./syntaxes/minbasic.tmLanguage.json"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,140 @@
|
|||||||
|
{
|
||||||
|
"scopeName": "source.mbas",
|
||||||
|
"fileTypes": [
|
||||||
|
"mbas",
|
||||||
|
"minbasic"
|
||||||
|
],
|
||||||
|
"name": "MinBasic",
|
||||||
|
"patterns": [
|
||||||
|
{
|
||||||
|
"captures": {
|
||||||
|
"1": {
|
||||||
|
"name": "punctuation.definition.comment.minbasic"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"comment": "Comment",
|
||||||
|
"match": "^ *(REM\\b|').*",
|
||||||
|
"name": "comment.line.minbasic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comment": "Delimiter",
|
||||||
|
"match": "[,:;]",
|
||||||
|
"name": "meta.delimiter.object.minbasic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comment": "Keyword",
|
||||||
|
"match": "(?i)(\\b((END ?)?IF|(END )?SELECT|(RESUME )?NEXT|CASE|CLOSE|DO|ELSE|FOR|GOSUB|GOTO|LOOP|ON|OPEN|RETURN|THEN|TO|UNTIL|WHILE)\\b)",
|
||||||
|
"name": "keyword.control.minbasic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comment": "Function",
|
||||||
|
"match": "(?i)(\\b(PRINT)\\b)",
|
||||||
|
"name": "support.function.minbasic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comment": "Operator",
|
||||||
|
"match": "(?i)((\\+|=|<|>|<>|AND|OR))",
|
||||||
|
"name": "keyword.operator.minbasic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comment": "Numeric",
|
||||||
|
"match": "\\b(\\d(\\.\\d)?)+",
|
||||||
|
"name": "constant.numeric.minbasic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comment": "Mindustry builtins",
|
||||||
|
"match": "(@(?:time|tick|unit|counter|this[xy]?|ipt|links|map[wh]))\\b",
|
||||||
|
"name": "constant.global.minbasic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"captures": {
|
||||||
|
"1": {
|
||||||
|
"name": "entity.name.function.minbasic"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"comment": "SUB",
|
||||||
|
"match": "(?i)(^ *(\\w+):)",
|
||||||
|
"name": "meta.function.minbasic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "meta.assignment.minbasic",
|
||||||
|
"match": "^ *((?i)LET +)([a-zA-Z_@#][a-zA-Z0-9_@#]*) *(=)",
|
||||||
|
"captures": {
|
||||||
|
"1": {
|
||||||
|
"name": "keyword.other.minbasic"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"name": "variable.other.minbasic"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"name": "keyword.operator.assignment.minbasic"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comment": "Brace, round",
|
||||||
|
"match": "[\\(\\)]",
|
||||||
|
"name": "meta.brace.round.minbasic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comment": "Brace, curly",
|
||||||
|
"match": "[\\{\\}]",
|
||||||
|
"name": "meta.brace.curly.minbasic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"begin": "(\\w+)(\\()",
|
||||||
|
"beginCaptures": {
|
||||||
|
"1": {
|
||||||
|
"name": "entity.name.function.minbasic"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"name": "meta.brace.round.minbasic"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"comment": "Function call",
|
||||||
|
"end": "(\\))",
|
||||||
|
"endCaptures": {
|
||||||
|
"1": {
|
||||||
|
"name": "meta.brace.round.minbasic"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "meta.function.call.minbasic",
|
||||||
|
"patterns": [
|
||||||
|
{
|
||||||
|
"include": "$self"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"begin": "(\")",
|
||||||
|
"beginCaptures": {
|
||||||
|
"1": {
|
||||||
|
"name": "punctuation.definition.string.begin.minbasic"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"comment": "String, double-quoted",
|
||||||
|
"end": "(\")",
|
||||||
|
"endCaptures": {
|
||||||
|
"1": {
|
||||||
|
"name": "punctuation.definition.string.end.minbasic"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "string.quoted.double.minbasic",
|
||||||
|
"patterns": [
|
||||||
|
{
|
||||||
|
"comment": "Escaped double-quote inside double-quoted string",
|
||||||
|
"match": "(\\\")",
|
||||||
|
"name": "constant.character.escape.minbasic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"comment": "Single quote inside double-quoted string",
|
||||||
|
"match": "(')",
|
||||||
|
"name": "other.minbasic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"include": "$self"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in new issue