
If it is necessary to guarantee that "not3" actually has three inputs and three outputs, the macro definition must explicitly perform the test, as illustrated in the next example.
not3: 'macro
'inputs 'a,'b'c
'outputs 'd,'e,'f
'if 'count('ilist)'!=3
'error s,"not3 should have 3 inputs"
'exit
'endif
'if 'count('olist)'!=3
'error s,"not3 should have 3 outputs"
'exit
'endif
not 'a,'d
not 'b,'e
not 'c,'f
'endmacro
This macro definition illustrates the use of several new features. First is the conditional statement 'if. An 'if statement must have one operand, and must be followed in the text by an 'endif statement. The operand is usually a conditional expression as shown in the example. The operators "'!=", "'==", "'<=", "'>=", "'<", and "'>" may be used to form conditional tests. (Note that each of these operators begins with an apostrophe.) The operators "&&", "||", and "!" (and, or, not) may also be used to form complex conditions. Of course, parentheses are also acceptable. If the condition is true, then the statements between the 'if statement and the 'endif statement are processed, otherwise they are skipped. A general arithmetic expression may be used as the operand of an 'if statement. When this is done, zero represents false and nonzero represents true. 'if statements may be nested arbitrarily. Each 'if statement must have a corresponding 'endif statement. As will be explained below, an 'if statement can be combined with an 'else statement and/or one or more 'elif (else-if) statements.
WARNING!! The operators "!=", "==", "<=", ">=", "<", and ">" are also treated as legal operators by the macro processor. HOWEVER, these operators are considered to be comparison operators used by other FHDL parsers. These operators will be passed through unchanged to the output. Check each of your comparison operators carefully to be sure that you have not used the wrong type. To guard against misuse of comparison operators, the macro processor will recognize the operators "$NE", "$EQ", "$LE", "$GE", "$LT" and "$GT" as valid comparison operators. Exclusive use of these operators will guard against problems with missing apostrophes.
The variables 'ilist and 'olist are built-in list-type variables whose values are the input list and output list of the macro call. The built-in function 'count may be applied to any list-type variable to obtain the number of items in the list.
The 'error statement is used to send error messages to the user. The first operand gives the severity of the message (i=information only, w=warning, s=severe(output terminated), t=terminal(immediate termination)). Anything other than these four letters will be interpreted as "t". The second operand is the text of the message to be sent to the user. The macro processor will add line numbers and file names to the message. Note that the message must be enclosed in quotes because it contains spaces. The 'exit statement causes processing of the current macro instruction to terminate. Processing of the input continues.
Now suppose we wish to enhance the not3 macro so that it will accept an arbitrary number of inputs and outputs, as long as the number of inputs and outputs is the same. We will call the new macro "not.m".
not.m: 'macro
'if 'count('ilist)'!='count('olist)
'error s,"not.m inputs and outputs don't match"
'exit
'endif
'int 'i
'assign 'i,0
'while 'i'<'count('ilist)
not 'ilist('i),'olist('i)
'assign 'i,'i+1
'endwhile
'endmacro
This macro illustrates several new features. First is the declaration of work variables. The 'int statement, which may have several arguments, declares one or more variables of type integer. Work variables may be of type integer, or of type string (declared with an 'str statement), or of type list (declared with a 'list statement). The 'assign statement can be used to assign new values to work variables.
The 'while statement, which must be followed by an 'endwhile statement, is used to repeatedly process a collection of statements. The operand of a 'while statement follows the same rules as the operand of an 'if statement. The statements between the 'while statement and its corresponding 'endwhile are processed repeatedly as long as the condition remains true. The rule stated above, that each statement is scanned for variables only once, must be modified for loops. Each statement in a loop is scanned only once each time it is processed. Processing a text statement does not change the statement, it merely causes output to be produced according to the instructions contained in the statement. While loops may be nested arbitrarily and may be combined arbitrarily with 'if statements.
The 'assign statement causes a value to be assigned to a variable. An 'assign statement has two operands, the first of which is the name of the work variable whose value will be changed. The second operand is an expression that, when evaluated, will produce the new value of the variable. The assign operator "<-" may be used instead of the 'assign statement. Thus the following two statements are equivalent.
'assign 'i,'i+1
'i<-'i+1
An expression may be a constant, such as 0, or the name of a variable such as 'i, or a complex expression involving constants, variables, operators, and built-in functions. A complete list of all operators and built-in functions will be found in the appendices. Among these operators are the arithmetic operators "+", "-", "*", and "/", and the comparison operators discussed above. The comparison operators return a 1 for true and a 0 for false when used as arithmetic expressions.
The built-in variables 'ilist and 'olist may also be used as built-in functions. When they are used as functions, they take one numeric operand that indicates a position in the input (or output) list. Positions are numbered from zero. The function returns the text of the operand in the specified position in the input (or output) list of the macro call. If the operand is greater or equal to the number of items in the input (or output) list, the null string is returned.
A 'while loop such as that illustrated in the previous example can be expressed more simply as a 'for loop, as illustrated in the following example.
not.m: 'macro
'if 'count('ilist)'!='count('olist)
'error s,"not.m inputs and outputs don't match"
'exit
'endif
'int 'i
'for 'i<-0,'i'<'count('ilist),'i<-'i+1
not 'ilist('i),'olist('i)
'endfor
'endmacro
The format of a 'for statement is given below.
'for exp1,exp2,exp3
<body>
'endfor
This statement is functionally equivalent to the following.
exp1
'while exp2
<body>
exp3
'endwhile
The first expression initializes loop values, the second is the condition under which the loop will continue to iterate, and the third expression is used to update loop variables for the next iteration. Any of the three expressions may be parenthesized lists of expressions, as the following "two-variable" loop illustrates.
'for ('i<-0,'j<-0),'i'<'ilim&&'j'<'jlim,('i<-'i+1,;j<-'j+1)
Loops can be terminated early by use of the 'break and 'continue statements. Neither of these statements takes any arguments. Executing the 'break statement causes the innermost loop to be immediately terminated.
Executing the 'continue statement causes the current iteration of the innermost loop to be immediately terminated. If the innermost loop is a 'for loop, the loop variables are updated. If the continuation condition of the 'for or 'while loop is still true, the next iteration of the loop begins.