- Latest version: 1.0.5
- Java SE 17: https://adoptopenjdk.net
- C Compiler (clang or gcc) for compiling shared libraries
- macOS: clang is provided by Xcode
- Linux (Ubuntu):
apt install clang
- Windows:
- clang (LLVM-[VERSION]-win64.exe): https://github.com/llvm/llvm-project/releases
- gcc (via MSYS2): https://packages.msys2.org/package/mingw-w64-x86_64-gcc
- macOS: Intel, Apple Silicon
- Remove the quarantine flag after downloading and unzipping:
xattr -c "Bahn IDE.app"
- Remove the quarantine flag after downloading and unzipping:
- Linux
- Windows
OVERVIEW: Bahn compiler 1.0.5
USAGE: bahnc [-o <path>][-r <route>] [-m <mode>] [-v] [-d] file
-o <path> output folder
-r <route> route generation mode (simple, extended)
-m <mode> code generation mode (default, c-code, library)
-v verbose output
-d debug output
EXAMPLE:
bahnc example.bahn
bahnc -r simple -m library -v example.bahn
bahnc -o output/src-gen example.bahn
-
Options and usage:
- Add
-o <path>
to change output folder. Default issrc-gen
- Add
-r <route>
to change the type of routes to generate.simple
only generates routes between any two signals with no intermediate signals.extended
generates routes between any two signals with zero or more intermediate signals - Add
-m <mode>
to specify the type of outputs to generate - Add
-v
to enable verbose output - Add
-d
for detailed log level (recommended for development only)
- Add
-
Examples:
- Generate YAML files (with simple routes) and SCCharts models with verbose output
bahnc -v example.bahn
- Generate YAML files (with extended routes) and SCCharts models
bahnc -r extended example.bahn
- Generate YAML files (with simple routes) and C code using embedded SCCharts compiler
bahnc -m c-code -v example.bahn
- Compile YAML files (with simple routes) and a shared C library using C compiler (cc/clang/gcc)
bahnc -m library -v example.bahn
-
Create a new project
- Click File -> New -> Bahn Project
- Specify a project name
- Click finish
- A new project is created, containing a default BahnDSL model, called
untitled.bahn
-
Create new BahnDSL model
- Click File -> New -> Bahn File
- Specify a file name
- A new BahnDSL model is created, containing an empty railway configuration model and interlocking functions
-
Output
- Generates YAML configuration files, SCCharts models, and a railway layout diagram in a
src-gen
folder
- Generates YAML configuration files, SCCharts models, and a railway layout diagram in a
-
Generate C code:
- Right-click on a Bahn model in the Project Explorer, and select "Generate C Code"
-
Compile into a shared C library:
- Right-click on a Bahn model in the Project Explorer, and select "Compile to shared C library"
- A BahnDSL model contains two parts: railway resource configuration and interlocking functions. A minimal Bahn model with all the necessary sections is shown below:
module standard
boards
master 0x00
end
segments master
end
signals master
end
points master
end
peripherals master
end
blocks
end
crossings
end
layout
end
trains
end
end
def request_route(string src_signal_id, string dst_signal_id, string train_id): string
return ""
end
def drive_route(string route_id, string train_id, string segment_ids[])
end
- The formal syntax of all elements is presented in the next section with examples
module module-name
boards
board
end
segments board-name
segment
end
signals board-name
signal
end
points board-name
point
end
blocks
block
end
crossings
crossing
end
layout
connector
end
trains
train
end
end
- Syntax
board-name hex-value
features
feature-hex-key : feature-hex-value
end
- Example
master 0xDA000D680052EF
features
0x03:0x14
0x6E:0x00
end
- Syntax
segment-name hex-number length number length-unit
- Example
seg1 0x00 length 10cm
- Syntax
signal-type-name signal-name hex-number
-
Signal type names are defined in the standard library
-
Composite signal (compound signal)
composite signal-name
signals
reference-signal-name-1
reference-signal-name-2
...
reference-signal-name-n
end
- Example
entry signal1 0x00
distant signal2 0x01
composite signal3
signals
signal1
signal2
end
- Syntax
point-name hex-number segment segment-name
normal hex-number
reverse hex-number
initial initial-aspect
- Example
point1 0x00 segment seg4 normal 0x01 reverse 0x00 initial normal
- Syntax
crossing-name segment segment-name
- Example
crossing1 segment seg35
- Syntax
peripheral-type-name peripheral-name hex-number port hex-number
-
Peripheral type names are defined in the standard library
-
Example
onebit lantern 0x0A port 0x0027
- Syntax
train-name hex-number steps number
calibration
[number]
end
weight number weight-unit
length number length-unit
type train-type
peripherals
peripheral-name bit number initial number
end
- Example
cargo_green 0x0006 steps 126
calibration
5 15 30 45 60 75 90 105 120
end
weight 100g
length 13cm
type cargo
peripherals
head_light bit 4 initial 1
end
- Syntax
block-name overlap segment-name main segment-name overlap segment-name
reversed limit number speed-unit
trains
train-type
end
- Example
block1 overlap seg20 main seg19 overlap seg18
trains
cargo
passenger
end
platform-name overlap segment-name main segment-name overlap segment-name
limit number speed-unit
trains
train-type
end
- Example
platform1 overlap seg36 main seg37 overlap seg38
- Syntax
element-name.endpoint connector element-name.endpoint
- Layout Connector
stem | straight | side | down | up | down1 | down2 | up1 | up2
- Example
point6.stem -- block1.down
point6.stem -- block1.down -- block1.up
point6.stem -- block1.down -> block1.up
request_route
is invoked by the SWTbahn-cli for selecting and grating route to traindrive_route
is invoked by SWTbahn-cli for monitoring physical track elements on the railway model during train driving sessionrequest_route
is required to build the interlocking shared library.drive_route
is optional.
def request_route(string src_signal_id, string dst_signal_id, string train_id): string
return ""
end
def drive_route(string route_id, string train_id, string segment_ids[])
end
- Four primary types:
int
float
bool
string
-
Object, struct or custom data type are not supported
-
Array is supported
-
Example
int index = 0
float rate = 0.5
bool valid = true
string text = "hello world"
string ids[] = { "route1", "route2" }
- Syntax
data-type name[]
- Example
int index
float rate
string ids[]
- Syntax
variable-name = expression
- Example
int index = 0
float rate = 0.5
bool valid = true
string text = "hello world"
string ids[] = { "route1", "route2" }
- Syntax
variable-name[index] = expression
- Example
string ids[] = { "route1", "route2" }
ids[0] = "route3"
- Syntax
def function-name(parameter-declaration-list): return-type
statement-list
end
- Example
def eval_str(string id1, string id2, string id3): string
return ""
end
def eval(string id1, string id2, string arr[])
end
- Syntax
function-name(argument-list)
- Example
string result = eval_str("a", "b", "c")
- Use
extern
to call externally defined C functions
string result = extern printf("Hello\n")
- Example
int index = 2
float rate = 0.5
bool is_success = true
bool is_failed = false
string text = "hello world"
int val = (3 + 4) * index
string ids[] = {"route0", "route1"}
string id = ids[0]
int size = ids.len
- Operators (absolute and relative)
* / % + -
*= /= %= += -=
- Example
int a = 3 + 4
float b = 3 + 4.5
int c = 4 % 5
float d = 65 / 100
int e = 3 + (4 * 5)
int e *= 3 + 4
-
Operators
- Relational:
> >= < <=
- Equality:
== !=
- Relational:
-
Example:
bool greater = 3 > 4
bool neq = "train1" != "train2"
-
Operators
- AND:
&&
- OR:
||
- NOT:
!
- AND:
-
Example
bool b1 = true && true
bool b2 = false || true
bool b3 = !b1
bool b4 = false || (b1 == b2)
-
Relative operators
- Bitwise AND:
&=
- Bitwise OR:
|=
- Bitwise XOR:
^=
- Bitwise AND:
-
Example
int b1 = 3 // b1 = 3 (0b0011)
b1 &= 1 // b1 = 1 (0b0001)
b1 |= 4 // b1 = 5 (0b0101)
b1 ^= 1 // b1 = 4 (0b0100)
-
Relative operators
- Shift left:
<<=
- Shift right:
>>=
- Shift right unsigned:
>>>=
- Shift left:
-
Example
int s1 = -3 // s1 = -3
s1 <<= 1 // s1 = -6
s1 >>= 1 // s1 = -3
-
Relative operators
- Max:
max=
- Min:
min=
- Max:
-
Example
int m1 = 5 // m1 = 5
m1 max= 1 // m1 = 5
m1 min= 10 // m1 = 5
m1 max= 20 // m1 = 20
m1 min= 0 // m1 = 0
- Syntax
if condition-expression
statement-list-then
else
statement-list-else
end
- Example
int a = 1
int b = 2
if a > b
return a
else
return b
end
- Syntax
while condition-expression
statement-list
end
- Example
int i = 0
int s = 0
while i < 10
s = s + i
i = i + 1
end
- Syntax
for var-decl in var-reference
statement-list
end
- Example
int nums[] = {1,1,2,3,5}
int sum = 0
for int n in nums
sum = sum + n
end
- Syntax
log primary-expression
- Example
log "message"
log (0.5 + 0.1)
log (1 + 2)
log (1 == 1)
- Check segment occupation (returns true or false)
bool is_occupied = is "seg1" occupied
- Check route availability (returns true or false)
bool is_available = is "route1" available
- Check whether an item is a segment (returns true or false)
bool is_segment = is "seg1" a_segment
- Check whether an item is a signal (returns true or false)
bool is_signal = is "seg1" a_signal
- Get signal state (returns "stop", "go", "caution", or "shunt")
string res = get state "signal1"
- Get point state (returns "normal" or "reverse")
string res = get state "point1"
- Set signal state (stop, go, caution, or shunt)
bool success = set state "signal1" to go
- Set point state (normal or reverse)
bool success = set state "point1" to normal
- Get train speed
int train_speed = get speed "cargo_db"
- Get config from YAML file (dot notation of the
schema
in the standard library)
string src = get config route.source "route1"
string segment_ids[] = get config route.path "route1"
- Get routes from interlocking table
string route_ids[] = get routes from src_signal_id to dst_signal_id
- Get expected point position in a route (returns "normal" or "reverse")
string pos = get position "point1" in "route1"
- Grant route
grant "route1" to "cargo_green"
Built-in functions in the standard library
- For a given array of routes, return the ID of the shortest route
def get_shortest_route(string route_ids[]): string
- For a given route, return the block that precedes
block_id
def get_previous_block(string route_id, string block_id): string
- For a given route, return the first block in the route with main segment equal to
segment_ids[0]
def get_block(string route_id, string segment_ids[]) : string
- For a given block, return whether it is occupied
def is_block_occupied(string block_id): bool
- For a given signal, return whether it is a composition of other signals
def is_composition_signal(string id): bool