Source Code Markup Language (SCML)

The Source Code Markup Language (scml) is a formatting language that can be used to create templates for source code that needs to be output by Flick. For example, the corba C++ mapping requires a number of C++ classes and functions to be generated alongside the actual defined types. These extra classes and functions are only there for the sake of presentation and do not need any special analysis or optimization so generating them is usually just a matter of plugging the right strings into a template. This phase of code generation can be done with a series of printfs, however, a more data oriented and externalized approach is more flexible and possibly easier to maintain. Therefore, scml was created so that the user could write the implementations of these functions as a template and data created by Flick would fill in the holes.

The use of scml code in Flick is currently limited to the functions and methods for the corba C++ classes created for the TAO implementation, although it would be nice to begin using it for other code which is currently done with printfs. This code is read in and executed at start up so that it can define a number of new commands that are used to generate the appropriate output. As a Flick back end then processes the pres_c and defers to the scml code whenever it encounters a presentation function declaration.

8.1 The Language

8.1.1 Introduction

The syntax of the language was based on SGML in an attempt to make it more accessible to people in general since many are already familiar with its most popular descendent, HTML. An example code section might be the best way to start.

The following scml code is taken from runtime/headers/flick/pres/std_defines.scml:
 <ifndef name="STD_DEFINES_SCML">
 <define name="STD_DEFINES_SCML" kind="static-variable" value=true>
 
 <!-- These are the standard set of defines used in SCML -->
 
 <define name="scope" kind="bracket-tag" value="c-scope-handler"
         rparams={name:string}>
 <define name="macro" kind="bracket-tag" value="c-macro-handler"
         rparams={name:string} oparams={close:bool=false
                                        rparams:tag_list={}
                                        oparams:tag_list={}}>
 ...
 </ifndef>

Anything within angle brackets is a command name followed by the arguments for the command. So the first command is ifndef, which is basically the same thing as a C preprocessor's `#ifndef', it checks to see if name has been declared or not and executes the block if it is not defined. The second command, define, creates a static variable in the current scope with the given name and value. From there we have a comment and then create some more commands for the system using define and then we terminate the ifndef block with </ifndef>. So this basically corresponds to the organization of a header file in C.

8.1.2 Types

Now that we know basically what a command looks like lets look a little deeper at the rest of the command. When executing a command there are a series of assignments after it that set the values of some variables. These assignments are setting the values of the parameters for the command. Each parameter has a name, which is the name used in the assignment, a type, which is specified in the definition, and finally a default value. A name can be any string, but only C style identifiers can be used regularly, otherwise one must surround the name with single quotes ('). The type of a parameter is currently limited to:

8.1.3 Values

The format for declaring the tag that represents this parameter is the tag name, a colon, and an equal sign followed by a literal value to set the default. For example, num:int=5 makes an integer tag named `num' and sets its value to 5, of course if this tag is not added to a list, it cannot be accessed and is lost, which is why all parameter declarations are tag_lists.

The set of literal values for these types are:

scml also supports simple expressions for most of its types:

8.1.4 Commands

In order to allow this language to be flexible enough to handle any type of presentation it has only a minor set of builtin commands from which all others are created. They are define, undef, rename, ifdef, ifndef, and include, although define is really the only one that is needed, the others are just there to be nice. Define is basically the hook that is used to add other objects into the system. It lets one create local variables, static variables, commands, and escape sequence for regular text. The parameters of the define command are:

The name, kind, and value parameters are required in order for define to work properly. From define there comes a standard set of commands that are useful, and cannot really be used to implement each other since they modify some scml execution state, they are:

In addition to regular style commands with names, there are a number of "special" commands which are denoted by some symbol. They are:

There is also a special tag which gets added to every block command. It is called `contents' and contains the scml code that is between its start and terminating commands.

8.1.5 Larger Example

Now lets look at some useful code:
 <macro name="idl" close=true rparams={type:string}>
 
   <scope name=type>
 
   <macro name="pres" close=true rparams={type:string}>
 
     <scope name=type>
 
     <macro name="func" close=true rparams={kind:string}>
 
       <macro name=kind oparams={sub_contents:scml=contents}>
         <pre><(sub_contents)></pre>
       </macro>
 
     </macro>
 
     <(contents)> <!-- put the contents of idl here so it can see 'func'-->
 
     </scope>
 
   </macro>
 
 </macro>

This code is used to setup some infrastructure that is used to actually define function bodies. The `idl' macro specifies an idl type (e.g., struct, union, etc.) and adds a new scope with that as the name. Inside of this scope it creates the `pres' macro which corresponds to a presentation type (e.g., var, out, etc.). Again a new scope is created with this name and we make the `func' macro which will be used to define a function body. Since just putting the contents of `func' right inside of the macro would print them out when the file is first being evaluated we make a new macro and pass our contents to it. This way when the Flick back end needs to output a function body it just looks up the right scope, grabs the macro and then executes it, thus printing out the function body. Now let's see this being used:
 <idl type="struct">
 
   <pres type="out">
 
     <func kind="T_out(T_ptr &)">
       : ptr_(<(parameter[0])>)
     {
       this->ptr_ = 0;
     }
     </func>
 
 </idl>

This code makes a macro named `T_out(T_ptr &)' inside of the struct::out scope. The presentation_impl inside of the back end now writes out the function type which it found in the cast and then looks up and executes this macro, resulting in the following output.
 blah_out::blah_out(blah_ptr &p)
   : ptr_(p)
 {
   this->ptr_ = 0;
 }

Notice that everything is spaced just fine. That is because func created the macro with `sub_contents' surrounded by the preformatting tag. Since preformatting causes indentation artifacts to be ignored they were ignored here, the important thing to note is that the indentation is based on the indentation of the block command that created the contants, not the one that used it.

8.2 The SCML interpreter

8.2.1 Introduction

The scml interpreter is contained in the C presentation back end library so all of the relevant sources are in c/pbe/lib/scml_*.cc and the header file is mom/c/scml.hh. The interpreter is primarily written in C++ with classes for the lexxer, parser, execution environment, and support for these. Using the interpreter is simply a matter of constructing lexxer, parser, and EE objects with an input file or string and then setting them in motion.

8.2.2 scml_stream

This class is used to hold any information about IO streams used in the code. The primary use of the class is for holding the input scml code in a string which is then used by the lexxer. However, these stream objects can also be used in scml code for setting the output stream with the create_stream and retarget commands.

char *tag_ref()
Make a TAG_REF string that refers to this object
static struct scml_stream *ptr(char *ref)
Convert a TAG_REF string into a scml_stream pointer
void set_flags(unsigned int the_flags), unsigned int get_flags()
Set/get the flags for the stream. Currently, the only flags are SSF_INPUT and SSF_OUTPUT, which correspond to whether the stream will be used for input or output.
void set_data(char *str), char *get_data()
Set/get a C string as the stream, this does not work for an output file.
void set_desc(char *desc), char *get_desc()
Set/get the description of the stream (e.g., file name)
void set_include_directory_list(char **dir_list), char **get_include_directory_list()
Set/get the list of directories in which to find any include files
int get_length()
Get the length of the stream
void set_file(FILE *file), FILE *get_file()
Set/get a file as the stream, if this is an input stream then it will read the whole file into memory for processing, otherwise it is just stored for later reference.

8.2.3 scml_string

The scml_string class is a bit of a hack to get around problems with using the pres_c tags as the representation of variables. The problem has to do with the tags being able to hold cast and scml not wanting to deal with anything language specific: it is only interested in strings, numbers, and the like. So the solution is to treat cast as "computed strings" and just place all strings inside of scml_strings so that we can still process regular strings and cast without too many problems.

char *tag_ref(), static struct scml_string *ptr(char *ref)
Encode/decode this scml_string object as a TAG_REF string.
static char *tag_string(tag_item *ti)
Attempts to construct a C string from a tag, this is done by getting a string directly from a TAG_STRING or doing a make_chars on an encoded scml_string object.
tag_data *add_component()
Adds another component to this strings. It is just like concatenating a string except it needs to be placed inside of a tag_data
void concat(struct scml_string *ss)
Concatenate an entire scml_string onto another one
int cmp(struct scml_string *ss)
Just like strcmp except it compares scml_strings
char *make_chars()
Tries to make a C string from this scml_string, it will fail if any of the components are "computed strings" (e.g., cast structures)
void print()
Print the string using wprintf

8.2.4 scml_token

The scml_token class is the primitive used to represent scml code and is used by almost every class that is a part of the interpreter. A token can be one of many kinds which may or may not have a value associated with it. Any values are contained within the value field of scml_token. The possible values it may hold are:

b
A boolean
i
An integer
f
A float
id
An identifier
str
An scml_string
text
Regular text
escape
The name of an escape sequence
ti
A tag_item
tl
A tag_list
children
The list of children for a non-terminal token

void strip()
If the token contains a tag this will try to make the token the same value as the tag. It can only fail if the tag does not have a corresponding scml type. Any other type of demotions, like float to int, need to be done explicitly by the user since information can be lost
void promote(int required_kind)
This will promote a literal value to a more complex scml type. For example, it can promote an integer to a float to make it easier for later stages to process.
int is_expr()
This will return true if the token represents some expression. For example, if it were an addition, subtraction, or just a plain value.
int is_value()
This will return true if the token contains a literal value
int is_operator()
This will return true if the token represents a mathematical operator
int is_container()
This will return true if the token represents some container, like a tag list, or an expression in parentheses.
int get_prec()
If the token represents an operator this will return its precedence
char *get_identifier()
If the token represents an identifier this will return a C string version. The possible type of identifiers include regular variable name, escape sequence names, and scoped names.
void print()
Used for debugging, just prints out the token

Each token also has a kind member which indicates what the token represents:

SCML_NONE
A null token, often used to indicate the end of a list of tokens
SCML_IGNORE
A null token, perhaps it once contained something meaningful, but should be ignored now. Or it is used when a token must be returned, but nothing meaningful was done.
SCML_ERROR
An error token, processing has resulted in an error
SCML_DONE
Indicates the end of the stream
SCML_COL_POS
The column position in the stream is in i so that it can be tracked and used in error reporting.
SCML_ROW_POS
The row position in the stream is in i so that it can be tracked and used in error reporting.
SCML_TERM_BOOL
A literal boolean value in b
SCML_TERM_INT
A literal integer value in i
SCML_TERM_FLOAT
A literal float value in f
SCML_TERM_STRING
A literal string value in str
SCML_TERM_TAG
A tag value in ti
SCML_TERM_TAG_LIST
A tag list in tl
SCML_TERM_TEXT
Any text from scml code that is not an escape sequence or a command is held in text
SCML_TERM_ESCAPE
The name of an escape sequence is in escape
SCML_TERM_ID
An identifier string is in id
SCML_TERM_VERBATIM
Any text within a verbatim command is in text
SCML_TERM_LPAREN
A left parenthesis
SCML_TERM_RPAREN
A right parenthesis
SCML_TERM_LBRACE
A left bracket `['
SCML_TERM_RBRACE
A right bracket `]'
SCML_TERM_LCURLY
A left curly brace
SCML_TERM_RCURLY
A right curly brace
SCML_TERM_SLASH
A forward slash, `/'. This token is only created for the forward slash immediately after an `<', otherwise an SCML_NT_DIV is created.
SCML_TERM_LT
A single less than sign, `<'. This token is used to signify the opening of a command, it is not the same as a less than inside an expression in the command.
SCML_TERM_GT
A single greater than sign, `>'. This token is used to signify the closing of a command, it is not the same as a greater than inside an expression in the command.
SCML_NT_COMMAND
A command with children pointing to the contents of the command. The token is a call to a tag if the first token is a SCML_NT_NAME followed by an SCML_NONE terminated array of expressions corresponding to the arguments. If the first token is an SCML_TERM_SLASH followed by an SCML_NT_NAME then the command is a terminator for the tag with that name. Otherwise the token can be just be an expression that will be printed later.
SCML_NT_SET
A converted SCML_NT_ASSIGN. It is a binary expression that indicates that the value of children[1] should be set in children[0]
SCML_NT_ASSIGN
An equal sign, `='. This token will be converted to an SCML_NT_SET for no real reason; it is legacy and the set should just be killed in favor of this token.
SCML_NT_PLUS
A plus sign, `+'. It is a binary expression so children[0] is the left side and children[1] is the right.
SCML_NT_MINUS
A minus sign, `-'. Also a binary expression so it is structured like SCML_NT_PLUS
SCML_NT_DIV
A division sign, `/'. Also a binary expression so it is structured like SCML_NT_PLUS
SCML_NT_MOD
A modulus sign, `%'. Also a binary expression so it is structured like SCML_NT_PLUS
SCML_NT_MULT
A multiplication sign, `*'. Also a binary expression so it is structured like SCML_NT_PLUS
SCML_NT_COLON
A colon, `:'. This token will immediately be converted into an SCML_NT_TAG when parsed.
SCML_NT_EQUAL
A C style equal sign, `=='. Also a binary expression so it is structured like SCML_NT_PLUS
SCML_NT_NOT_EQUAL
A C style not equal sign, `!='. Also a binary expression so it is structured like SCML_NT_PLUS
SCML_NT_LT
A double less than sign, `<<', used in expressions since a single one is already used to demarcate a command.
SCML_NT_GT
A double greater than sign, `>>', used in expressions since a single one is already used to demarcate a command.
SCML_NT_LE
A less than or equal sign, `<='. Also a binary expression so it is structured like SCML_NT_PLUS
SCML_NT_GE
A greater than or equal sign, `>='. Also a binary expression so it is structured like SCML_NT_PLUS
SCML_NT_LAND
A C style logical and sign, `&&'. Also a binary expression so it is structured like SCML_NT_PLUS
SCML_NT_OR
An or sign, `|', used for doing union operations on tag lists.
SCML_NT_LOR
A C style logical or sign, `-'. Also a binary expression so it is structured like SCML_NT_PLUS
SCML_NT_NOT
A exclamation mark, `!', that signifies a logical not on children[0]
SCML_NT_DOT
A dot, `.', used for referencing tags within a tag list.
SCML_NT_SCOPE_RES
A C style scope resolution operator, `::'. Also a binary expression so it is structured like SCML_NT_PLUS
SCML_NT_NAME
A null token that indicates the token in children[0] can be used as a name.
SCML_NT_EXPR
A null token that indicates the token in children[0] is some kind of an expression
SCML_NT_TAG
A tag declaration converted from an SCML_NT_COLON. The tag name is contained in children[0] and the name of the type is in children[1]
SCML_NT_SEL
A slot selection on an array variable. This token is created from a pair of brackets with children[0] expecting to resolve to a tag and children[1] evaluating to an integer.
SCML_NT_COMMA
A comma, `,', used when separating the elements of a tag list.
SCML_NT_INIT
An initialization contained in curly braces. This is a bit hacky since one can create an array initializer, or a tag list, depending on what kind of data is in the initialization.
SCML_NT_COND
A conditional expression similar to the one in C, `<test expr> ? <expr> : <expr>', except it is not implemented yet.
SCML_NT_AND
An ampersand, `&', used for to do intersection on a tag list, if it was implemented.
SCML_NT_XOR
A carat, `^', for doing exclusive ors, except it is not implemented.

8.2.5 scml_token_sequence

An scml_token_sequence is used to reference sections of scml code. The class tracks the position and the origin of the code so it is possible to format the code correctly, and point out where any errors are in the source.

char *tag_ref(), static struct scml_token_sequence *ptr(char *ref)
These are used to encode and decode the token sequence as a TAG_REF style string. This allows the sequence to be passed around and used in scml code
void print()
Used for debugging, just prints the contents of the sequence out
void set_value(struct scml_token *st), struct scml_token *get_value()
Set/get the array of the tokens that represent the value of this sequence
void set_length(int len), int get_length()
Set/get the length of the array of tokens in this sequence
void set_stream_pos(struct scml_stream_pos *ssp), struct scml_stream_pos  *get_stream_pos()
Set/get the stream position object used when parsing the tokens in the sequence. This is mainly here for error reporting when the tokens get processed
void set_indent(int offset), int get_indent()
Set/get the column based indentation of the tokens. This allows users of scml to structure their code with indents without having it affect the way it will eventually be printed, even when preformatted.

8.2.6 scml_token_stack

The scml_token_stack is a support class for the parser that just maintains a stack of tokens.

void push(struct scml_token &st), void pop()
Push/pop a token
struct scml_token *index(int offset)
Access the token at the given offset from the top of the stack
int count()
Returns the number of tokens on the stack
void print()
Used for debugging, just prints out the contents of the stack

8.2.7 scml_stream_pos

The scml_stream_pos is used to lex the scml source and for tracking the position during execution. The class is slightly different from a regular lexxer since it needs to operate in two modes, one for the raw text, and one for the command tokens. Additionally, the class also needs to return position tokens so that it is possible to accurately track position in the source during execution. Otherwise, the operation of the class is like one would expect, it translates text into tokens for others components to process.

void set_stream(struct scml_stream *ss), struct scml_stream *get_stream()
Set/get the data stream for lexxing
void set_flags(unsigned int the_flags), unsigned int get_flags()
Set/get the flags
void set_state(int state), int get_state()
Set/get the state
void set_cursor(char *cursor), char *get_cursor()
Set/get the current position in the scml_stream buffer
void set_row(int row), int get_row()
Set/get the current row in the stream
void set_column(int column), int get_column()
Set/get the current column in the stream
int get_last_row(), int get_last_column()
Get the last row/column that was lexxed in the stream. This is used in error messages to give the user a range to look for the error
char *munge_string(char *str)
Convert a string with escape sequences into a standard C string.
int get_number(struct scml_token *st)
Convert a number in the text stream and store its value in st.
int scan(int kind, const char *str)
Scan forward in the stream until the condition is satisfied, the cursor will then be placed one character after the cause of the stop.
struct scml_token get_token()
This is the main function for lexxing, it will walk through the stream returning tokens until it hits the end of the stream and returns SCML_DONE

8.2.8 scml_parser

The scml_parser is a simple (and not very good) parser for scml tokens returned by an scml_stream_pos. It works by giving the class an scml_stream_pos and then calling parse. If the parse was successful a token sequence will be returned which can then be executed.

void set_stream_pos(struct scml_stream_pos *ssp), struct scml_stream_pos  *get_stream_pos()
Set the stream that the parser should get tokens from.
struct scml_token_sequence *parse()
The main parsing function, it will ask the stream position object for tokens and then construct an scml_ token_sequence from them.
struct scml_token collapse(struct scml_token_stack *values, struct scml_token *oper)
An internal function used when parsing. Basically, it just looks at the operator and pulls any operands off of the stack, and then pushes the operator connected to the operands onto the values stack.

8.2.9 scml_handler

The scml_handler is a structure for binding a name to a C/C++ function, making it easy to bind to a function from an scml level.

8.2.10 scml_handler_table

The scml_handler_table class is used for tracking and indexing all of the functions available.

void add_handler(struct scml_handler *sh), void rem_handler(cosnt char *name)
Add/remove a handler in the table
struct scml_handler *find_handler(const char *name)
Find a handler in the table with the given name

8.2.11 scml_cmd_definition

The scml_cmd_definition class is used for describing an scml command, its name, parameters, and definition.

char *tag_ref(), static struct scml_cmd_definition *ptr(char *ref)
Encode/decode the object as a TAG_REF compatible string
void set_name(const char *name), const char *get_name()
Set/get the name of the command
void set_opt_params(tag_list *tl), tag_list *get_opt_params()
Set/get the list of optional parameters
void set_req_params(tag_list *tl), tag_list *get_req_params()
Set/get the list of required parameters
void set_flags(int flags), int get_flags()
Set/get the flags for the object
void set_handler(struct scml_handler *sh), struct scml_handler *get_handler()
Set/get the handler for this command.
void set_token_sequence(struct scml_token_sequence *sts), struct scml_token_sequence  *get_token_sequence()
Set/get the token sequence that defines this command
int execute(struct scml_token *st, struct scml_context *sc)
Execute the handler with the token and context

8.2.12 scml_escape/scml_escape_table

The scml_escape class is used for describing an scml escape, the name and value. The escapes are then tracked in an scml_escape_table.

void add_escape(struct scml_escape *se), void rem_escape(cnst char *name)
Add/remove an escape definition in the table
void find_escape(const char *name)
Find an escape definition with the given name

8.2.13 scml_scope

The scml_scope class is used to represent a scope in scml, it holds definitions, child scopes, and escapes. Static variables and command definitions are held in the values tag list, but escapes are held separately.

struct scml_scope *get_parent()
Return the parent scope
void set_name(const char *name), const char *get_name()
Set/get the name of the scope
void set_escape_table(struct scml_escape_table *setable), struct scml_escape_table  *get_escape_table()
Set/get the escape table associated with this scope
void add_child(struct scml_scope *ss)
Add a child scope
struct scml_scope *find_child(const char *name)
Find a child scope
void add_cmd_definition(struct scml_cmd_definition *scd), void rem_cmd_definition(struct  scml_cmd_definition *scd)
Add/remove a command definition in the scope
struct scml_cmd_definition *find_cmd_definition(struct scml_scope **scope, const char  *name)
Return the command definition with the given name or NULL if it was not found. The scope it was actually found in is set in scope.
tag_list *get_values()
Return the tag_list with the list of global variables
void print()
Debug printf
static struct scml_scope *make_root_scope()
Construct an scml_scope that is suitable for use as the root scope. Basically, it just adds all the builtin command definitions

8.2.14 scml_context

The scml_context class is used to execute scml code and actually generate the resulting output. The primary function is format_sequence which takes a token sequence (e.g., from an scml_parser::parse()) and then executes the contents, printing out text tokens and evaluating expressions. Execution of scml commands will create a child context for which the command executes in, of course, if the command is implemented by a C function it can manipulate its parent context, allowing for great flexibility.

void set_flags(int flags), int get_flags()
Set/get the flags for the context
void set_parent(struct scml_context *parent), struct scml_context *get_parent()
Set/get the parent context
void set_stream_pos(struct scml_stream_pos *ss), struct scml_stream_pos *get_stream_pos()
Set/get the scml_stream_pos object which was used in lexxing the code
void set_cmd_def(struct scml_cmd_definition *def), struct scml_cmd_definition  *get_cmd_def()
Set/get the command definition associated with this context
void set_lvalues(tag_list *tl), tag_list *get_lvalues()
Set/get the left hand side values
void set_rvalues(tag_list *tl), tag_list *get_rvalues()
Set/get the right hand side values
void set_scope(struct scml_scope *sc), struct scml_scope *get_scope()
Set/get the current scope
void set_indent_size(int size), int get_indent_size()
Set/get the indent size. This size corresponds to how much indentation there is before a macro call, so that any preformatted text in the macro will be aligned with the beginning of the call instead completely left justified.
void set_offset_size(int size), int get_offset_size()
Set/get the offset size. This size corresponds to the difference between the start of a line and the position of a pre command. The size is then used to determine when to start printing leading spaces in a line, thus, it is possible to indent scml code with having the indentation affect the output.
int print_token(struct scml_token *st)
Prints out the contents of a token. The token should already have been evaluated so only tokens with literal values should be passed to the function.
void print_indent(int size)
A simple function to print an indentation of the given size.
void locate_scope(struct scml_token *st, struct scml_scope **inout_scope, const char  **out_id)
int equalize_tokens(struct scml_token *dest, struct scml_token *src, int count)
Converts the count sized array of tokens into the simplest common type. The process is to strip all of the tokens in src and then try to promote them all to the same type. If a common type was found, it will be returned and dest will have the converted tokens, otherwise SCML_ERROR is returned.
struct scml_token eval_token(struct scml_token *st)
Evaluate a token expression to produce a token that has a printable value, except for commands, which have to be handled by exec_token.
void token_lvalue(struct scml_token *st, tag_item **out_ti, int *out_index)
Get the lvalue of a token. Since all variables are really just tags, the result is a pointer to the tag_item and, if it is an array, the index into the array.
int handle_params(struct scml_token *cmd)
Processes the SCML_NT_COMMAND token to evaluate each argument and set its value in the context.
void tag_type(struct scml_token *t_type, tag_data_kind *out_kind, int *out_size)
Determine the pres_c tag type needed to hold an scml value.
struct scml_cmd_definition *find_cmd(struct scml_scope **cmd_scope, struct scml_token  *st)
Find the command definition referenced by the token
void define(struct scml_context *sc)
Handles the define command which is used to define other commands, escapes, and variables. This is executed on the parent context and a child context is passed in which contains all of the arguments. The method will then pull any arguments of interest from the sc context and define the object.
void undefine(struct scml_context *sc)
Undefine an object that was previously defined.
void rename(struct scml_context *sc)
Rename an object
int ifdef(struct scml_context *sc, struct scml_token_sequence *sub, int defined)
Similar to the define method, this will handle the ifdef and ifndef builtin commands. If the defined parameter is true then it will act like ifdef and execute the contents if the object is defined, otherwise it acts like ifndef and executes when it is not defined.
struct scml_token_sequence *get_contents(struct scml_cmd_definition *def, struct  scml_token_sequence *sts, int start)
Return the contents of a bracketed command in a token sequence. The passed in token sequence and start parameter indicate where the start of the command contents is located which the function then scans through looking for the terminator. Once the terminator is located it will create a new token sequence and set it to contain the contents.
struct scml_token_sequence *partition_sequence(struct scml_cmd_definition *def, struct  scml_cmd_definition *partition, struct scml_token_sequence *sts)
Partitions a token sequence around a given command. The passed in sequence will be adjusted to contain the first part of the partition and a new sequence will be created with the second part. This is useful for bracketed commands that have several different sections. For example, it can be used to separate the true and false branches of an if test, or for the cases in a switch.
int exec_token(struct scml_token_sequence *sts, int *index, struct scml_token *st)
Execute a token, if the token is a command it will consume the tokens of the body, if it is bracketed, and then call the handler for the command. If the token is a simple value then it will be printed.
int format_sequence(struct scml_token_sequence *sts)
Executes the commands and prints out any text in a token sequence.
int exec_cmd(const char *cmd_name, tag_list *locals, ...)
Manually execute a command. The locals argument is set as the parent tag list of the context that the command is executed in so it is possible to get at the values. The varargs portion of the call is used to add values directly to the context and is a formatted set of values. The first value is a string corresponding to the name of a variable, next there is a tag_kind specifying the type of the variable, and finally a tag_data_u which contains the value of the variable.
static void set_handler_table(struct scml_handler_table *sht), static struct  scml_handler_table *get_handler_table()
Set/get the handler table where handlers specified in defines will be found. This table is global to all contexts so only one table needs to be constructed.
void print(int level)
Print a stack trace for debugging

8.2.15 Command Handler Functions

Any builtin commands not handled by the scml_context are handled by C functions. These functions are defined in c/pbe/lib/scml_context.cc and then a number of scml_handlers are created for each and added to the handler table in the scml_context.

int c_defvar_handler(struct scml_token *st, struct scml_context *sc)
Handles the defvar command by walking the child tokens of st and evaluating them and adding the tags they create to the context.
int c_ignore_handler(struct scml_token *st, struct scml_context *sc)
Handles the ignore command by walking the list of child tokens and evaluating them, without doing anything else. The evaluated expressions are expected to create some kind of side effect.
int c_scope_handler(struct scml_token *st, struct scml_context *sc)
Handles the scope command by changing to, or creating the scope with the given name. The parent scope is set to the new scope and then the parent context executes contents of the scope on behalf of the child.
int c_macro_handler(struct scml_token *st, struct scml_context *sc)
Handles the macro command by creating a new command that will execute the contents of the macro when used.
int c_macro_executer(struct scml_token *st, struct scml_context *sc)
Handles commands that have been created using the macro command. It will evaluate the arguments and then get the macro body from the command definition and execute the scml code.
int c_if_handler(struct scml_token *st, struct scml_context *sc)
Handles the if command by evaluating children[1] of st to get a value to test for being true or false. Then it will try to partition the contents of the command around the else command. Finally, it tests the expression and executes the true or false branch accordingly.
int c_else_handler(struct scml_token *st, struct scml_context *sc)
Handles the else command by signalling a runtime error since the command is only meant for use as a partition inside of an if.
int c_for_handler(struct scml_token *st, struct scml_context *sc)
Handles the for command by creating the loop variable in the context and then executing the contents for however long has been specified.
int c_pre_handler(struct scml_token *st, struct scml_context *sc)
Handles the pre command by setting the SCF_PREFORMATTED flag and the offset of size of the contents block in the parent before using the parent to execute the contents.
int c_aliascmd_handler(struct scml_token *st, struct scml_context *sc)
Handles the aliascmd command by building a new command with the same definition as the command specified by the handler argument.
int c_include_handler(struct scml_token *st, struct scml_context *sc)
Handles the include command by executing the file specified by the file argument. The file is searched for in the include directory list of the stream the current file was read.
int c_retarget_handler(struct scml_token *st, struct scml_context *sc)
Change the output file to the one specified by the `output' parameter, which should resolve to an scml_ stream.
int c_create_stream_handler(struct scml_token *st, struct scml_context *sc)
Create an scml_stream object and set its file to the one specified by the `path' argument, or stdout if path is empty. The object will then be added as a static variable to the current scope with the name specified by the `name' argument. This is a big hack.

8.2.16 Miscellaneous Functions

These functions are just simple helper functions to make life a little easier.

void scml_alert(struct scml_stream_pos *ssp, int alert_flags, const char *format, ...)
A printf like function for reporting errors/warnings when executing scml code. The stream position argument is optional and currently only used to print out the column and line number of code that is causing the problem. The alert_flags argument is a bitfield used to describe the alert. The possible flags are:
SAF_WARNING
This is a warning
SAF_ERROR
This is an error
SAF_INTERNAL
The problem is internal
SAF_GENERAL
The problem cannot be classified
SAF_IO
The problem is with I/O
SAF_LEXICAL
The problem is with lexxing
SAF_PARSE
The problem is with parsing
SAF_TYPE
The problem is with bad/inconsistent types
SAF_RUNTIME
The problem is with the execution environment

int init_scml()
Does any initialization of scml structures. Currently, this just initializes the handler table with all of the builtin command handlers.
const char **scml_std_include_dirs()
Returns an array of strings which are paths that it can find include files. The array is the same kind that fopen_search so it can be used directly with that functions.
int scml_hash_name(const char *name, int table_size)
Produces a hash number for name in a table the size of table_size
int scml_parse_cmdline_defines(struct scml_scope *root_scope, flag_value_seq *defs)
Evaluates the flag value sequence to create the desired scml variables. The flags are expected to be formatted strings of the form, `var=expr', where `var' is the variable name, and expr is the typed value of the expr. If there is no expression then a boolean variable is defined and set to true.
int scml_execute_str(struct scml_scope *root_scope, char *code_desc, char *code, tag_list  *tl)
Execute scml `code' in the `root_scope' with `tl' holding any implicit values. The `code_desc' argument is used as the description for the scml_stream so that one can figure out what scml code caused an error.
struct scml_stream_pos *scml_execute_defs_file(struct scml_scope *root_scope, const char  **include_dirs, const char *file_desc, const char *file_name)
Execute a file that will only define objects and not produce any output.
int scml_code_cast_handler(int indent, cast_handler *ch)
A routine for executing scml code that is encapsulated by a cast_handler object. The cast_handler is set up with this routine as the handler and four arguments for the scml code. The arguments in order are the code description for the scml_stream, the scml code itself, a TAG_REF encoded pointer to an scml_scope to execute in, and finally a tag_list of implicit arguments.