VAPPad
- VAPPad
VAPPad is a VAP file editor, bringing the modern IDE features to the VAP editing.
VAPPad 1.0 is ready and can be downloaded as part of VHelper 3.1 suite to increase your productivity.
Installation
No installation is required, just download the zip file, unzip and double click vappad.exe to run.
Click here to go to download page
For trial purpose, you need request an activation code for the full features.
Features
In addition to the syntax highlighting
Live Errors
VAPPad shows you syntax and semantic errors immediately. No need to wait starting the VISSIM simulation. This should save you the back and forth time between VISSIM and a regular editor and is particularly useful when you have a large VISSIM network which takes long time to start.
Errors are shown as squiggles and in the error list.
Another example - Subroutine not defined
To see full list of errors VAP can squiggle, scroll down to the section before the VAP language introduction.
Statement Completion
You can manually trigger VAP keywords and 68 internal functions with the usual shortcuts: Ctrl+Space
.
Auto Format
Automatically indent and beautify your code to improve readability.
Function Quick Info
Hover over internal functions to see a Quick Info tooltip.
Function Parameter Info
Move the caret in the function arguments to match the corresponding parameters.
Macro Drop-down List & Folding
Shows available macros and navigate to the corresponding one after selection. Collapse and expand the macros.
Delimiter Matching
Press "Ctrl+]" when next to a parenthesis ()
or bracket []
to navigate to its
matching delimiter, or "Shift+Ctrl+]" to select to its matching delimiter.
Word Highlighting
Highlight the same token
Mor Errors that VAPPad can Squiggle
Function arguments need to be numbers, constants or variables but not composite expressions.
Mismatched number of function parameters
Integer literal out of range
Trace
variable takes maximum 2 variablesStatement function such as
set_sg
used as expressionExpression function such as
presence
used as statement
VAP Programming Language Introduction
Overview
VAP (vehicle actuated programming) is an optional add-on module of VISSIM for the simulation of programmable, phase or stage based, traffic actuated signal controls.
The latest version of VAP interpreter DLL is 2.16-16 (2016-08-15) at this time of writing.
VAP language itself is a dynamic, case insensitive, single scope (global scope), procedural programming language. It is similar to Python or Lua.
A First Program
PROGRAM New;
VAP_Frequency 1;
CONST
/*********CONSTANTS***********/
MaxGreen2 = 50,
MaxGreen4 = 80;
ARRAY
/***********ARRAYS************/
field[3,4] = [[0, 3, 4.6, 1.23], [1.3, 4, 0, 0.1], [1, 2, 3, 4]],
tClearance[4] = [0,3,0,3];
SUBROUTINE test1;
/*
IF Not init THEN
Set_sg( 1 , off );
LowOccFlag := 1;
init := 1;
END;
*/
x := 1
.
SUBROUTINE test2;
y := 2
.
/**** BEGIN MAIN SECTION ****/
GOSUB test1;
GOSUB test2
.
It consists of 6 sections: Program, VAP_Frequency, Const, Array, Subroutine(s) and main sections.
VAP_Frequency, Const, Array and Subroutine(s) are optional, but the order matters. For example, if you put VAP_Frequency after the Const segment, you will get an error.
Program Header, Controller Frequency, Constants and Array must end with a semicolon. Subroutine(s) and main sections must end with a dot .
If you define a segment, the contents of that segment can not be empty. the following empty subroutine will have parse error
/* empty subroutine will cause parse error */
SUBROUTINE test1
.
Program Header
The first command of a VAP program (in a *.vap file) must consist of the keyword PROGRAM
, the name of the program (as a valid identifier) and a semicolon ;
.
Controller Frequency
This declaration consists of the keyword VAP_Frequency
, an integer value between 1 and 10 (the number of passes through the VAP logic per simulation second - default value is 1 if skipped) and a semicolon ;
.
The controller frequency needs to be a factor of the simulation resolution (time steps per simulation second).
Constants
User defined constants can be defined in this section.
A definition consists of identifier, an equal sign =
and constant value. If you have multiple constants, separate them by comma ,
, then end with a semicolon ;
.
An equal sign must be used, :=
is considered as an assignment statement.
If you try to re-assign a value to a constant, VISSIM will report an error
CONST
MaxGreen2 = 50,
MaxGreen6 = MaxGreen2, /* OK, bound to a previous defined constant */
MaxGreen4 := 50; /* Error, must use =, not :=*/
MaxGreen8 := MaxGreen3; /* Error, MaxGreen3 is not defined before/
/* In the Subroutine or Main Segment */
MaxGreen2 := 100; /* Error, re-assign a constant */
Array
Array (up to two dimensional) can be defined in the Array section.
Unlike typical C family language, array values are initialized by the same bracket []
as in the rank definition, instead of braces {}
ARRAY
tClearance[4] = [0,3,0,3];
Subroutines
A subroutine can not be empty, and it must end with a dot .
, and there is no explicit return command.
Any number of subroutines may be defined (only limited by RAM space). Any predefined subroutine can be called inside a program using the GOSUB
command.
You can call another subroutine within a subroutine. Multiple Subroutine order does not matter in the sub sections, unlike functions in C language.
Unlike VAP 2.16 manual says on page 10
However, there is no form of recursion allowed. Therefore the currently active subroutine cannot call itself.
I find that a recursion is allowed and you can use GOSUB
to call the subroutine itself, as long as you provide an termination criteria not go into endless loop.
Main Segment
Like subroutines, it consists of multiple statements delimited by semicolon ;
. The main program can not be empty and must end with a dot .
.
Everything after .
of main segment is ignored, so make sure all your subroutines are defined before the main program segment.
Language Elements
Identifiers
An identifer is a name used to identify a variable, a constant, a subroutine or a label. An identifer must start with a letter followed by zero or more letters, underscores and digits (0 to 9).
a := 1; /* OK */
a10 := 10; /* OK */
a_number := 10; /* OK */
2b := 5; /* Error, starts with digit */
_cd := 6; /* Error, starts with underscore _ */
b# := 10; /* Error, invalid char # */
$m := 10; /* Error, starts with $ */
VAP is not case sensitive, abc and ABC points to the same variable. IF and if are considered as the same keywords.
Keywords
PROGRAM VAP_Frequency CONST ARRAY SUBROUTINE
IF THEN ELSE END
GOSUB GOTO WAIT_AT UNTIL
TRACE NOTRACE COMMAND ALL VARIABLE
AND OR NOT
START STOP RESET
keywords can not be used as variable, constant, subroutine and label name
VAP has 68 internal functions, those names are reserved too. For example
Cycle_second T Umlaufsekunde T
Cycle_time Tc Umlaufzeit Tu
Detection Det Anmeldung Anm
Front_ends F_e Vorderkanten Vka
Intergreen Intg Zwischenzeit Zz
...
Please note every function has an English long name, English short name, German long name and a German short name.
zz := 10; /* Error, zz is a short German name for Intergreen function */
VAP also has 11 signal display constants reserved as keywords.
Display | Meaning |
---|---|
amber |
|
amber_f |
(amber flashing) |
greenamber |
|
green |
|
green_f |
(green flashing) |
redgreen_f |
(red-green alternating) |
red |
|
red_f |
(red flashing) |
redamber |
(red and amber together) |
off_red |
(off meaning ‘red’) |
off |
(off meaning ‘green’) |
Variables
VAP has two types of variables, regular and timer variables. All variables reset to zero when the simulation starts.
You use START
, START_AT
, STOP
and RESET
to change timer variables. Once a timer variable is started, its value is increased by the length of the controller time step (reciprocal of the controller frequency) at the start of each pass through the logic.
Start (phase2Clearance);
...
Stop (phase2Clearance);
Reset (phase2Clearance);
Timer variable cannot be changed later by an assignment statement, and vice versa. For example, if you try to assign phase2Clearance to 4, VISSIM will report an error.
phase2Clearance := 4; /* Error, can not assign a timer variable */
a := 10;
Start(a); /* Error, can not start/stop/reset a normal variable */
VAP has dynamic type system, a variable can be assigned to integer, then bound to a double later.
x := 10;
x := 3.14; /* do this is fine, rebound to a double floating point number*/
If a varialbe is initialized, but never used later, there will be a warning for this.
There is no local scope in VAP, all variables and constants are at global scope, a variable defined in one Subroutine can be accessed or reassigned in another subroutine or main segment.
Operators
VAP has the following operators, start with the highest precedence to lowest
Precedence | Operator | Meaning |
---|---|---|
6 - Highest | () | Parentheses |
5 | NOT | logical NOT (unary) |
4 | AND | logical AND (binary) |
4 | * , / | Multiplication, Division |
4 | % , \ | Modulo, integer division |
3 | OR | logical OR (binary) |
3 | + , - | Addition, Subtraction (binary) |
2 | =, <>, <, <=, >, >= | comparison |
1 | - | negate (unary) |
All operators are left-associative. The precedence order is different from well established norms in C family, I personally feel this is against my expectation and should stick to the C common convention.
- Negative operator has the lowest precedence
a := 2 + -1; /* Error */
a := 2 - -1; /* Error */
a := 2 - (-1) /* OK, Wrap in () */
a := -3 - 2; /* What's the value? it is -5 as expected, seems evaluated as (-3)-2, this is against the precedence order, should be => -(3-2) => -1 */
b := 4 Or -1; /* Error */
b := 4 And -2; /* Error */
- Logical
And
andOr
has the same or higher precedence than arithmetic operators
if 1 + 1 = 2 And 2 - 2 = 0 then /* parse error */
end
if (1 + 1 = 2) And (2 - 2 = 0) then /* use (), OK */
end
if 3 > 2 and 2 > 1 then /* parse error, however technically it parse => 3>1>1 => 1>1 => False(0)*/
end;
v := 5-2 Or 2-1; /* the value is 0, because OR has same precedence as +/-, => 3 Or 2 -1 => 1 - 1 => 0 */
w := (5-2) Or (2-1); /* as expected 3 Or 1 => 1 */
y := -2 and 4; /* the value is -1 as expected */
x := -2 or 4; /* the value is 1, NOT expected, seems VAP evaluated as (-2) or 4, however following precedence table strictly, unary - should have the lowest precedence, then should be evaluated as - (2 or 4) */
c := 5-2 and 2-1; /* the value is 3 as expected, and has the higher precedence => 5-1-1=>3 */
d := (5-2) and (2-1); /* the value is 1 as expected => 3 and 1 =>1 */
e := 2 or 2 + 1; /* the value is 2 as expected => 1 + 1 => 2 */
f := 2 or (2 + 1); /* the value is 1 as expected => 2 or 3 => 1 */
if -10 * 2 + 10 = -10 then /* Technically it should not parse and VAPPad flag this, however VAP evaluate this expression to true, seems treated (-10) * 2 + 10 = (-10)*/
y := 1
else
y := 0;
end;
it is strongly recommended to use parenthesis to denote what exactly you want
Comments
- no single line comments such as
//
in C# and Java - only multiple line comments
/* */
- matching is greedy, after starting delimiter
/*
, it will continue and skip any letters including other/*
until meet end delimiter*/
, which means nested comments block are not valid
/* /* ok comments */
/* /* invalid nested comment blocks */ */
Types
Numbers
Integer and double floating point numbers. Integer must be within [-2147483639, 2147483639], which is different from typical 32 bit integer range in C# or Java [-2147483648, 2147483647].
Floating number must start with a digit and no scientific notation is allowed either.
x := 10; /* OK */
y := 3.14159; /* OK */
a := .5 /* Error */
b := 1.54334E16 /* Error */
c := 2147483647 /* Error, out of range */
big := 2147483650.2 + 10.2; /* value is 2147483660 using trace, seems rounded */
No string types
Boolean
0 is false, any non zero is true. All variables reset to zero when the simulation starts
if -1 then
x := 10;
else
x := 5;
end
if 0 then
y := 10;
else
y := 5;
end
The value of variable x is 10, y is 5
a := 1 and 2;
b := not a;
The value of variable a is 1, b is 0
Please note there are no boolean literals, True or False, they are interpreted as undefined variables
if 10 > 1 = True then
x := 1; /* this never will get executed */
end
if TRUE then
a := 1;
else
a := 0;
end;
What's value for variable a
? Yes, it's 0
Statements
Assignment Statement
Simple assignment to a variable is how you create a new variable or rebind an existing one to a new value.
x := 1
Please note use :=
not equal symbol =
Array value can also be on the left side of assignment statement
arr[3] := 10
Gosub Statement
The GOSUB command calls the specified SUBROUTINE. After executing the subroutine, program execution continues with the next command following the GOSUB command.
If Statement
IF-THEN-END
or IF-THEN-ELSE-END
, the expression following the key word IF
is evaluated first. If the result is other than 0, the statements following THEN
will be executed. Otherwise, the program execution will be continued either with the statements following the optional ELSE
-clause or with the statements following END
if there is no ELSE-clause.
IF 1 > 0 THEN
a := 5
ELSE
a := 10
END;
The semicolon at the last statement of THEN
block and ELSE
block is optional.
Goto Statement
There is no While or For loops in VAP, use Goto. Program execution continues at the command referenced by the jump label identifier following the jump command.
The jump label identifier must be directly followed (maximum of one blank space) by a colon
WAIT_AT-UNTIL Statement
The WAIT_AT-UNTIL
command can be used to assemble a time loop. Firstly the expression following UNTIL
is be evaluated. If its value is zero(false), program execution is interrupted for the current controller time step and will continue in the next controller time step, repeating the evaluation of the expression following the WAIT_AT command. Otherwise, program execution continues with the next command after the label following WAIT_AT
.
WAIT_AT Stage1 UNTIL t_actual = T1;
Functions
Following functions can be used as statement in VAP
Clear_front_ends
Clear_rear_ends
Interstage
Marker_put
P_interstage
Record_value
Reset
Set_cycle_second
Set_des_speed
Set_prog
Set_route
Set_sg
Set_stop_time_dist
Sg_green
Sg_red
Start
Start_at
Stop
All the rest of functions like Presence
can only be used as expressions.
x := Presence (2) /* any vehicle front ends detected on detector #2 */
Functions below have to be used like a constant, no parentheses ()
are used
Cycle_second/T
Cycle_time/Tc
Tele_count
Prog_active
t_actual := Cycle_second - offset;
Trace Statement
Like Console.log()
in javascript, you can use Trace
to print out the variables and more. Please see the manual for detailed description.
Trace(All);
Trace(Command);
Trace(Variable(x, y));
NOTRACE;
Use NOTRACE
to deactivates the trace mode and writes a line of “+” signs in the trace file in order to document the end of the latest trace protocol.
Possible Manual Problems
Page 10 recursion in Subroutine
no form of recursion allowed for subroutine. Therefore the currently active subroutine cannot call itself.
This is in contrast to the change log in Doc folder
Version 2.14 [VAP214.EXE, VAP214_E.EXE] (2002-12-05)
Subroutines can call each other and themselves (recursively).I have done some tests, it does allow recursion.
- Page 13
Gosub
statement example - should not haveEND
at the end of CalcSignalState subroutine.End
is only forIF
block. - Page 13
IF-THEN-ELSE-END
, if the result is other than 0, thefollowingexpression(s)
THEN
will be executed. It should bestatement(s)
followingTHEN
. Same thing toElse
-clause. - Page 14
Timer
commands example,if noTimer = TRUE THEN
, there is no literal forTRUE
,TRUE
is treated as an undefined variable. - Page 27 example for
Stage_duration
function. This is wrong,Wait_at
should be followed by a label, not by statement(s).
Notes
- Symbol
:=
is used in the assignment. Though it's a good practice to separate assignment and comparison equal symbols, 95% time are spent writing statements. I am used to use equal symbol=
for assignment. Can't tell you how many times I got:=
expected errors. I would suggest VAP swap:=
and=
for constant definition and assignment. - Semicolon
;
is optional for the last statement of theTHEN
andELSE
block; this with the requirement that no semicolon for the last statement in the subroutine or main segment, adds some unnecessary complexities in writing the parser. - I have done several hand-written top down parsers before and have used parser generators such as ANTLR and Irony. I also did parser combinators with pattern matching in functional language such as F#, so I don't consider myself a total newbie. However I still spend time doing some unnecessary tricks to get the semicolons to work. As in real life, too many choices often make life harder. By requiring the semicolon at each statement end just like C# or Java, the grammar could be beautifully written as
'Subroutine' id ; (statement ;)+ .
- In addition, adding a block structure would be nice, like use dot
.
to denote both the beginning and end of the block. This could simplify the parser more and make things such as code reformatting easier. Because block can be beautifully recursively defined as a kind of statement too.