Home Reference VEX 

Vex compiler (vcc)

Overview of how to use the VEX language compiler vcc and its pre-processor and pragma statements.

The vcc compiler compiles VEX source code into a form executable by Houdini. The VEX compiler (vcc) is capable of compiling VEX code, generating dialog scripts for VEX functions, and also giving quick help by listing the global variables and functions available in any given context.

Command-line options

-?, -H, -h

Show help message for the compiler.

-X context_name

Display a list of a global variables, statements, and functions which are valid in the given context. The available contexts are listed in the help message (vcc -h).

-D name=def, -D name

Define a macro for the pre-processor. If no value is given with the name, the name is defined as 1.

-I path

Add the path specified to the include path (the list of directories search for files referenced by the #include directive to the pre-processor). The standard Houdini include path is under vex/include.

-o file

Output to file rather than putting compiled .vex code in the current directory. If you use stdout as the filename, the output is redirected to STDOUT.

-c

Generate a binary/encrypted version of the file . The generated .vex code will not be human-readable. You can also use the #pragma crypt pre-processor directive to only encrypt certain blocks of code.

-e file

Redirect errors from STDERR to file.

-w wlist

Suppress printing of certain warnings. wlist is a comma-separated list of warning numbers to suppress.

-q, -Q

Quiet. Lower-case q suppresses normal messages. Upper-case Q suppresses messages and warnings. Both options still print errors.

-i

Make the generated .vex code more readable by indenting the output based on nesting.

-u, -U

Generate a corresponding dialog script for the VEX function. Houdini can use the script to create a window to let the user modify parameters interactively (rather than editing a string). If you use -U, only the dialog script file is generated (the code is not compiled).

-g n

When generating dialog scripts with the -u or -U option, automatically creates tabs for each group of n parameters. You can manually group parameters with the #pragma group pre-processor directive.

-v

Extract parameter information and build a dialog script from compiled .vex code. You should only use this option if you can’t generate the dialog script from the original source code (the compiled code does not include any of the pragma information from the source).

Preprocessor

The compiler has a pre-processor which strips comments, expands macros, and optionally encrypts the output.

The pre-processor supports many of the usual C Pre-Processor directives:

#define name token-string

Replace subsequent uses of name with token-string.

#define name(arg,...,arg) token-string

Replace subsequent instances of name with token-string. Each argument to name is replaced in token-string during expansion.

#undef name

“Undefine” the macro so subsequent uses of name are not expanded.

#include "filename"

Inserts the contents of the file at this point in the source code. When you use quotes, the directory containing the current file is searched for filename before the standard locations (including the path).

#ifdef name

The following lines until the next #endif or else directive will be compiled if and only if name is a defined macro.

#ifndef name

The lines following will be compiled if and only if name is not a defined macro.

#if constant-expr

The following lines until the next #endif or #else directive will be compiled if and only if constant-expr evaluates to non-zero.

The expression can use the following operators:

  • Comparisons (==, !=, <=, >=, <, >)

  • Logical AND (&&), OR (||), and NOT (!).

  • Bitwise AND (&), OR (|), exclusive OR (^), and NOT (~).

  • Arithmetic (+, -, *, /, %).

  • Parentheses.

The expression can also use the following functions:

defined(name)

Returns 1 if the name is a defined macro, or 0 if it is not.

#if defined(foo) && defined(fum)
environment(name)

Returns 1 if name is a defined environment variable.

access(filename)

Returns 1 if filename can be read by the application, or 0 if the file cannot be read.

#if access("/etc/passwd")
#include </etc/passwd>
#endif
strcmp(str1, str2)

Works the same as the C/C++ function of the same name, if the two strings have the same contents, the function returns 0. Each argument should be a quoted string or a macro that expands to a quoted string.

#define VALUE "foo"
#if strcmp(VALUE, "bar") != 0
This statement is false since "foo" != "bar"
#endif
#if !strcmp(VALUE, "foo")
This statement is TRUE since strcmp("foo", "bar") == 0
#endif

Expressions are evaluated from left to right (unlike the ANSI C standard of right to left). As with the ANSI pre-procssor, all numbers must be integers.

#else

The following lines until the next #endif directive will be compiled if and only if the previous #if directive evaluated to non-zero.

#endif

Marks the end of a section of conditional code. Every test directive must have a matching #endif.

#pragma ...

Specifies extended language features. See the list of pragmas.

Predefined macros

The following macros are pre-defined:

__vex

This symbol is always defined. You can use this in an if pre-processor directive to check that the program is being compiled by vcc.

__vex_major

The major version number of the compiler.

__vex_minor

The minor version number of the compiler.

__LINE__

The current line number of the source file.

__FILE__

The file being compiled.

__DATE__

The current date (as a quoted string). Example: "Dec 31 1999"

__TIME__

The current time (as a quoted string). Example: "23:59:59"

printf("Starting shader %s at %s", __FILE__, __DATE__);

Code encryption

In some cases you may want to produce compiled code that is not human-readable. For example, your code may contain proprietary algorithms you don’t want to become public knowledge.

You can encrypt an entire file with the -c compiler flag, or mark a block of code to be encrypted with the #pragma crypt and #pragma endcrypt pre-processor directives:

float
wavenoise(float height, float distance)
{
#pragma crypt
return sin(distance)*height;
#pragma endcrypt
}
When this code is compiled it is encrypted to be reasonable secure.

You may sometimes need to encrypt the proprietary information in the source code (especially since vcc doesn’t support linking in library code). You can use the vcrypt utility to encrypt the parts of the source code designated by #pragma crypt. The compiler will be able to read and compile the encrypted source code.

If the compiler detects encrypted source in its input stream, the final output will be encrypted. This means it’s not possible to reverse engineer an encrypted function by compiling it and decoding the assembler output.