cc
cc configuration files
Introduction
cc reads commands from the configuration file, and executes them to run the appropriate compiler and linker. The command line that was passed to cc is examined by the code in the configuration file. If you are familiar with MKS Toolkit, you may notice that the commands resemble AWK or MKS KornShell commands. However, these commands are sufficiently different that you should study them carefully before using them. Look at sample configuration files, and experiment with cc in its interactive mode as you program new configuration files. The program tries to load the script $ROOTDIR/etc/compiler.ccg. You can modify this behavior by setting the CCG environment variable. If CCG contains the name of a file, cc loads and runs that file; if CCG contains the name of a directory, the program loads and runs the script in that directory.
If you rename the cc executable, it attempts to find its default configuration in a .ccg file with the same base name as the renamed executable. For example, if you rename cc.exe to c89.exe, then c89 looks for a default configuration file named c89.ccg in ROOTDIR/etc.
In any case, if you have set the CCG environment variable, its value takes precedence. If CCG contains a file name, cc looks for the default configuration in that file. If CCG contains a directory, cc looks for the default configuration in a .ccg file in that directory. The base name of the .ccg file is the same as that of the executable. That is, if the executable is cc.exe, the default configuration is looked for in $CCG/cc.ccg and if the executable has been renamed c89.exe, the default configuration is looked for in $CCG/c89.ccg.
To enter interactive mode, set the environment variable CCG to the value - or stdin. cc then reads its configuration file from its standard input. This is useful for debugging new configuration files: you can interactively enter commands, dump cc's symbol table, and follow the execution of your cc program.
Comments
A comment starts with a # character and extends to the end of the line. This is the same convention as MKS Make, AWK, and the MKS KornShell.
Literals
cc can manipulate three types of objects: integers, strings, and arrays of strings or integers. Since arrays are limited to one dimension, they are also called vectors. Unlike AWK, cc does not support floating point numbers.
Integers are written in the usual way. Here are some sample integers:
123 -49 20000
Strings are written with quotes around them, and cannot extend across a line. Empty strings are written as "". The following escape sequences are allowed within strings:
\a alert (bell)
\b backspace
\h hard space
\i hard tab
\n newline
\r carriage return
\t horizontal tab
\v vertical tab
\\ escaped \
\" embedded "
\ooo ASCII character with octal value ooo
Here are some sample strings:
"hello" "\"embedded\" quotes"
"\\escaped backslash, with tab\t and newline\n"
A vector is list of integers or strings, separated by commas and surrounded by braces, as in
{ 1, 2, 3 }
{ "strings", 1, "and numbers" }
{ a++, ++c }
{ }
Because these are dynamic, the contents of the vector need not be constant expressions. For example, a++ is valid in a vector list. Empty vectors are written as {}. You indicate a vector's elements with the bracket [] operator.
Indexable Objects
Both strings and vectors can be indexed -- indexing is 0-origin. Indexable objects have an associated cursor that indicates the current position of the index. This means you can treat any indexable object as a stream. (The cursor is actually associated with the value of a variable rather than with the variable itself; if you assign a new value to a variable, the cursor is reset to the origin.) The rewind statement lets you rewind the stream to the start of an object. Several functions are provided for dealing with indexable objects --read(), offset(), and tail().
# Setup the string:
stream="Alph" ;
# Read and print the first 3 elements;
# this prints "A l p"
println read(stream), read(stream), read(stream);
# Rewind the stream:
rewind(stream);
# Print the first two elements
# and the index of the next ("A l 2"):
println read(stream), read(stream), offset(a);
# Print the remainder of the string ("ph"):
println tail(stream);
To look ahead on a stream, use indexing combined with the offset. See “String/Vector Operations” below for more information on the functions.
Variables
A variable is a name with an associated value. The name follows the usual rules for C identifiers; the first character must be a letter or underscore (_), followed by zero or more letters, digits, or underscores.
Variables are created as they are first seen in cc input. Any variable can have any type of value; the type changes automatically if a value of a different type is assigned.
BUILT-IN VARIABLES
Several variables have pre-assigned values at the start of a cc program. You can change these values. The variables are:
• ARGV
This variable is assigned a vector containing the strings that appeared on the command line that called cc. Note that the name of the program is not provided. ARGV is typically examined, and used to build new argument lists for the compiler or linker that is being used.
• DIRSEPSTR
Contains the characters that can be used to separate path names into the component directories. On Windows systems, it is initially set to the string /\:. although the default startup.mk file modifies this based on the value of the SHELL environment variable. See the description of filepath().
• ECHO
Originally assigned the empty (null) string, corresponding to a false expression. If it is later assigned a true value, the exec and ovl_exec operations (described later) print the commands as they are about to be executed.
• NORUN
Originally assigned the empty (null) string, corresponding to a false expression. If it is later assigned a true value, the
exec and
ovl_exec operations (described later) only echo their arguments, and
exec returns as though the command succeeded, while
ovl_exec terminates
cc with a return value of 0. Setting
NORUN in this way corresponds to running Make with the
-n option. By assigning non-null values to both
ECHO and
NORUN, you can get
cc to display the commands that it attempts to execute to compile a program.
• true
Assigned the integer value 1,
true is used internally by
cc to denote a true expression. You should not change this value; if you change the value of
true to be an expression that is considered false (see “EXPRESSIONS” below),
cc may not function correctly.
Programs
A
cc program consists of a number of statements, each of which is read and then executed. During the reading of a statement, a syntax error causes cc to print a diagnostic message, and then cc goes on to the next statement. During the execution of a statement, an error causes
cc to print a diagnostic message. If cc finds a syntax error as it is reading a statement, it prints a diagnostic message and goes on to the next statement. While executing a statement, if cc finds an error, it prints a diagnostic message; if an expression is being calculated, then the null string is returned as the value of the expression.
STATEMENTS
This section describes the statements that may be used in input to cc. In the following, the characters {} are used to indicate zero or more occurrences of the enclosed items. The characters [] indicate an optional occurrence of the enclosed items.
The following table summarizes statements allowed in cc:
Summary of cc Statements
Description
|
Syntax
|
Advance
|
advance name
|
Assignment
|
name = expr
name[expr1] = expr2
|
Assign & concatenate
|
name |= expr
name[expr1] |= expr2
|
Break loop
|
break [expr] ;
|
Close file
|
closefilename ;
|
Delete file
|
deletefilename ;
|
Dump debugging info
|
dump ;
|
Empty statement
|
;
|
Execute command
|
exec expr ;
|
Exit
|
exit ;
|
For
|
for (name in expr)
do statements done
|
For
|
for (expr1; expr2; expr3)
do statements done
|
Functions
|
function name([arg1{[,arg2]]})
{ statements }
|
If
|
if (expr1) statements
{ elif (expr2) statements }
[ else statements ]
fi
|
Open file
|
open filename ;
|
Overlay file
|
ovl_exec cmd_expr1 {,expr2} ;
|
Print expression(s)
|
print expr1 {,expr2} ;
|
Print line
|
println expr1 {,expr2} ;
|
Print to file
|
print expr1 {,expr2} -> filename;
println expr1 {,expr2} -> filename;
|
Rewind cursor
|
rewind indexable_object
|
While
|
while (expr) do statements done
|
In this definition, statements means a list of statements, and expr, expr1, and expr2 mean any legal expression as described a bit later. The expression value is used as a logical expression. See “EXPRESSIONS” below for the description of what values are considered true and false.
• Empty statement
◦ An empty statement is written as a single semicolon (). It has no effect.
• If statement
◦ An if statement has the form:
if ( expression ) statements
{ elif ( expression ) statements }
[ else statements ]
fi
Note that fi is required to end the if statement. Any number of elif's can be inserted before the end of the if statement.
• While statement
A while statement has the form:
while ( expression ) do statements done
The done is required to mark the end of the statements. The meaning is similar to the C while loop.
• For loop
A for statement has one of these forms:
for ( name in expression ) do statements done
for ( expr1expr2expr3 ) do statements done
In the first form, the name must be a variable name, and the expression must evaluate to a vector or string. If the vector is not empty, the statements are executed repeatedly; on each iteration, name is assigned each successive value in the vector. The second form is much more like the C language for loop. Usually, the first expression initializes some variable, the second expression tests it, and the third expression increments or decrements it.
• Advance
An advance statement has the form:
advance name
where name is a variable name used in an enclosing for loop. This statement immediately assigns to name the value it would normally have been given in the next iteration of the for loop, and subsequent iterations skip this value.
• Break loop
A break statement has the form:
break [expr] ;
where expr is the number of levels to break out of. If no expression is specified, break exits the current loop (expr is 1).
• Exit Program
The exit statement has the form:
exit expression
This terminates
cc with the integer-valued expression as its exit value.
• Dump Debugging Information
The dump statement is a debugging aid.
dump ;
outputs the names and values of all variables currently defined to the standard output.
• Print Expression
There are several printing statement forms.
print expression { , expression } ;
prints the values of the given expressions on the standard output. If more then one expression is given, they are printed with a single blank separating each item. print does not put a newline character at the end of the output.
println expression { , expression } ;
is similar to the previous format, but does print a newline at the end of the list of expressions.
print expression { , expression } -> filename ;
println expression { , expression } -> filename
are similar to the other printing statements, but they print to the given file instead of to the standard output. The filename is given as a string-valued expression. If the file does not exist, it is created; if it already exists, output is appended to the end of the current contents.
• Close File
To close a given file, use
close filename
The filename is given as a string-valued expression. If you use a printing statement to write to a file, it is important to close the file before cc runs a program that requires the contents of the file to be up-to-date.
• Delete File
To delete a given file, use
delete filename
You can use this to get rid of temporary (work) files created by earlier statements in the cc program. The file name is given as a string-valued expression.
• Define Function
You can define a function using the function statement, which has the form:
function name ( [arg1{, arg2}] )
{
statements
}
• Execute a command
To execute a command, use
exec expression { , expression } ;
Each expression is converted into a string (if necessary) and then concatenated into a command string (with a single blank between each expression in the list). For example,
exec "cp","infile","outfile" ;
executes the command
cp infile outfile
The exec statement executes the command and then goes on to the next statement. (See the exec expression following for ways to get the return status of the executed command.) The behavior of exec can be changed by the values of the ECHO and NORUN variables.
• Overlay Execute
The statement
ovl_exec expression { , expression } ;
is similar to an exec statement. In this case, the memory used by cc is overlaid with the command to be run, and cc is effectively terminated. This frees the memory space that cc is occupying for the executed program. The behavior of ovl_exec can be changed by the values of the ECHO and NORUN variables.
• Rewind Stream
The rewind statement has the form:
rewind indexable_object
where indexable_object is a string or vector. This statement moves the cursor associated with indexable_object back to the origin. For more about indexable objects, see the section Indexable Objects.
EXPRESSIONS
Expressions are created by combining literal strings, integers, vectors, and variables, with the operators listed a bit later.
An expression has a type: integer, string, or vector. When an integer value is required and a string or vector is provided, some operators convert the vector into a string, and then interpret that string as an ASCII sequence representing a number. For example, "123" has the integer value 123 when used in arithmetic operations. By the same token, if a string is required, an integer value is converted into a string in the same way.
Some expressions are calculated by determining if operands are true or false. The following are considered false:
• the integer 0
• the null string ""
• an empty vector { }
Other objects are considered true. The built-in variable true can also be used as a condition.
Operators are grouped in precedence classes that are similar to those of the C programming language. Each section that follows describes a group of operators in a single-precedence class. The order of the sections gives the order of precedence.
cc Order of Operations
Order of Operations
|
A++ A-- ++A --A
|
pre- and post-increment and decrement
|
-A (A) V[a]
|
unary minus, grouping, array element
|
A*B A/B
|
integer multiplication and division
|
A+B A-B
|
addition and subtraction
|
A%B
|
modulus
|
:
|
|
A==B A!=B
|
equality comparison
|
A<B A>B A<=B A>=B
|
relational comparison
|
A&&B A||B !A
|
logical AND, logical OR, logical negation
|
,
|
|
->
|
file redirection
|
length(A)
|
length operation
|
A | B
|
string/vector concatenation
|
A=B A|=B
|
assignment
|
A and B are any expression.
|
|
V is any vector expression.
|
|
Primary Expressions
These expressions have the highest precedence.
- expression
gives the negative of an integer expression.
( expression )
gives the value of the expression inside the parentheses, and you use it to change the order of evaluation of expressions.
indexable_object[expression]
obtains the value of a specific indexable element. Indexable objects (vectors and strings) are indexed with 0-origin. If a vector subscript is out of range, an error message is displayed, and the null string is returned. As a special case, the 0-th element of a 0-length vector does not cause an error; instead, its value is the null string.
Arithmetic Operators
The standard multiplication operators are:
expression1 * expression2
expression1 / expression2
expression1 % expression2
representing integer multiplication, division, and the modulus. Non-integer operands are converted to integers in the usual way.
The standard addition operators are:
expression1 + expression2
expression1 - expression2
representing addition and subtraction. Non-integer operands are converted to integers in the usual way.
Equality Operators
The result of:
expression1 == expression2
is true if the two expressions have equal values.
expression1 != expression2
is true if the two expressions are not equal.
In both cases, if either operand is an integer, the other is converted into an integer for the purposes of comparison; otherwise, both expressions are converted into strings, and then compared.
Relational Operators
The relational operators are:
expression1 > expression2
expression1 <expression2
expression1 >= expression2
expression1 <=expression2
The value of these expressions is true if the given relationship is true. If one operand is an integer, the other is converted to an integer (if necessary) and the comparison takes place numerically; otherwise, operands are compared as strings, according to the ASCII collating sequence.
Logical Negation
The expression
! expression
is true if expression is false, and false if expression is true.
Logical Conditional Expressions
The conditional AND expression has the form:
expression1 && expression2
The value of this expression is false if expression1 is false, in which case expression2 is not evaluated; otherwise, if expression1 is not false, the value of the expression is the value of expression2.
The conditional OR expression has the form:
expression1 || expression2
If expression1 is not false, the value of the expression is that value, and expression2 is not evaluated; otherwise, the value of the expression is the value of expression2.
Length Operation
The length operation has the form:
length (expression)
If expression is a vector, the value is the number of elements in the vector. If expression is a string, the value is the number of characters in the string; otherwise, the value is 0.
String/Vector Operators
The operator | concatenates strings or vectors. The form is
expression1 | expression2
where expression1 must be a string or vector. If expression1 is a string, the second argument is converted to a string and the two strings are concatenated for the result. For example, in
X = "hello";
X = X | " good" | "bye";
the variable X is assigned the value
"hello goodbye"
You can use the shorthand notation |= to append to the end of an existing string, as in
x = "hello";
x |= " good" | "bye";
which has the same result.
If the first argument of the | operator is a vector, the second argument is added as a new component to the vector. In this way, you can assign values to a vector incrementally. You can use the |= operator as a shorthand assignment. For example:
x = {} # ensure x is a vector
x |= 1; # x is now { 1 }
x |= "so"; # x is now { 1, "so" }
x |= 2 | 3; # x is now { 1, "so", "23" }
# Remember, the '|' is applied to '2' and '3',
# forming a string, that is then added
x |= { 4, 5 }; # x is now { 1, "so", "23", 4, 5 }
Assignments
There are several assignment expressions.
name = expression ;
assigns the value of the expression to the given named variable.
name[expression1] = expression2
assigns the value of expression2 to the element of the vector variable specified by expression1. It is an error to use an index greater then the length of the vector.
name |= expression ;
name[expression1] |= expression2 ;
are concatenation assignments. The value of the right hand side is concatenated to the existing value of the left hand side. See “String/Vector Operators” below for more about concatenation.
Because assignments are expressions, rather than statements, they can be used anywhere. For example, this is valid:
if (a = 2)
println "true" ;
fi
String/Vector Operations
There are a number of other string/vector operators, summarized in this table:
Summary of cc Functions
Function
|
Description
|
access(filename,[num|str])
|
return true if filename's mode is str or num
|
cd(pathname)
|
change to named directory
|
cinclude(filename)
|
include filename; return 0 if it does not exist
|
exec(expression {, expression})
|
execute command line
|
filepath(expression)
|
return vector containing path name components
|
getcwd()
|
return current working directory path
|
getenv(name)
|
return value of environment variable name
|
getopt([str[, optind]])
|
process options string
|
include(filename)
|
include filename; abort if filename does not exist
|
index(str,expr)
|
return index of first expr in str
|
isatty(fileno)
|
return true if fileno is a tty
|
offset(indexable_object)
|
return cursor offset in indexable_object
|
ovl_exec()
|
execute command line in overlaid memory
|
putenv()
|
alter value of environment variable
|
read(indexable_object)
|
return next token from indexable_object
|
replace(str,old,new)
|
return str with old replaced by new
|
rindex(str,expr)
|
return index of last expr in str
|
sleep(num)
|
sleep for num seconds
|
strerror()
|
return string corresponding to errno
|
substr(expr,pos)
|
return substring of expr starting at pos
|
substr(expr,pos,len)
|
return length len substring of expr starting at pos
|
tail(indexable_object)
|
return unread portion of indexable_object
|
tempfile([dir_str,] pre_str)
|
temporary file name
|
tolower(expr)
|
return expr in lowercase
|
toupper(expr)
|
return expr in uppercase
|
unix_path(name)
|
return name as a UNIX path name
|
windows_path(name)
|
return name as a Windows path name
|
• access(filename, [mode])
Returns true if the access mode of filename is the same as the supplied mode. The mode should be passed as a string composed of the characters r, w, x, or f (for read, write, execute, or file existence). If no mode is supplied, f is assumed.
access("temp.af9","f") -- checks if temp.af9 exists
access("temp.af9","rw") -- checks for read/write
permission on temp.af9
If the base operating system allows, mode can be passed as a number. This is non-portable, so you should use a string representation.
• cd(pathname)
Changes the current directory to the value of pathname.
• cinclude(filename)
Includes the specified file. No path search is performed. If filename is not an absolute path name, the current directory is searched. If the file does not exist, this function returns 0; otherwise, it returns 1.
• exec(expression {, expression})
Is similar to the exec statement. The value of an exec expression is the exit status of the last command executed. This is an integer.
• filepath(expression)
Returns a vector whose components are the strings corresponding to the path name components of the string expression. The built-in variable DIRSEPSTR is used to determine the components of the path.
• getcwd()
Returns the current working directory path.
• getenv(name)
Returns the string value of the environment variable indicated by the string expression name. If the environment variable is not set, the null string "" is returned.
getopt([optstr[, optind]])
Processes an option string; this simplifies the business of writing scripts that take options. optstr is a format string listing each option character; if the option character is followed by a colon, the option takes an argument. For example, the format string "aei:o:u" specifies that the options a, e, i, o, and u are valid, and the colons show that both i and o require arguments. The option being processed is stored in a variable; if there is an argument, it is stored in the global variable OPTARG.
optstr only needs to be specified on the first call. Subsequent calls to getopt() continue processing the same ARGV argument string. Here is a bit of code that sets flag variables for each option called:
while (opt = getopt("dl:rtx")) do
if (opt == "d" ) d_flag++;
elif (opt == "l" )
l_flag++;
l_arg = OPTARG;
elif (opt == "r" ) r_flag++;
elif (opt == "t" ) t_flag++;
elif (opt == "x" ) x_flag++;
fi
done
The getopt call does not remove items from the ARGV string, it just moves the OPTIND pointer through the ARGV vector. If you want to pass the tail of the argument string without the options, you can reset the value of ARGV with code like this:
members = {};
for (i=OPTIND; ARGV{i}; i++) do
members |= { ARGV[i] );
done
ARGV = members;
• include(filename)
Includes the specified file. No path search is performed. If filename is not an absolute path name, the current directory is searched. If the file does not exist, the script aborts.
|
Expressions are compiled completely and then executed. As a result, if you use include in a function, the file is not included until an expression referencing the function is executed.
|
• index(expression, string-expression)
Returns the index of the first occurrence of string-expression in the expression If the first expression is a vector, it is irst converted into a string. The index is 1-origin; a value of 0 is returned if the second expression is not a substring of the first.
• isatty(filenum\)
Returns true if filenum is a tty; filenum is an integer representing a file number. The values 0, 1, and 2 represent standard input, standard output, and standard error, respectively.
• offset(indexable_object)
Returns the current stream offset in an indexable object.
• ovl_exec(expression {, expression})
Constructs a command line in the same way, and then overlays
cc with that command.
cc exits with the exit code returned by that command.
• putenv(string)
Where string is a string expression of the form name=value assigns value to the environment variable indicated by the string expression name and adds that variable to the current environment.
• read(indexable_object)
Reads the next item from indexable_object and returns it.
• replace(string, old, new)
Returns string with all occurrences of the first character of the string old replaced with the first character of the string new.
• rindex(expression, string-expression)
Is similar to index but returns the index of the last occurrence.
• setformat(filename, format)
Sets the file character format to the specified format. File character formats are described on the unicode reference page and format must be one of the values described there.
• sleep(num)
Sleeps for num seconds.
• strerror()
Returns the string that corresponds to the current value of errno. If errno is not set, returns a null string.
• substr(expression, position)
Returns the substring of the first string, starting at the position given by the second argument (an integer expression). Strings are 1-origin; however, for convenience, if the value of position is 0, substr returns the substring beginning at 1. If position is negative, it is taken to be an offset from the end of the string. For example:
substr("hello",0) = substr("hello",1) -> "hello"
substr("hello",length("hello")) -> "o"
substr("hello",-3) -> "llo"
substr("hello",-1) -> "o"
substr may also take three arguments, as in:
• substr(expression, position, length)
The length argument is an integer expression, giving the desired number of characters in the substring. If this value is negative, the substring is obtained by advancing to the indicated position, marking that the end, and then retreating by the specified amount. For example:
substr("hello",0,1) = substr("hello",1,1) -> "h"
substr("hello",-1,-3) -> "llo"
• tail(indexable_object)
Returns the unread portion of an indexable_object.
• tempfile([dir_str], pre)
Returns a string guaranteed to be an unused temporary file name in the directory specified by dir_str. If no dir_str is provided, then the directory specified by TMPDIR is used; if TMPDIR is not set, the system default is used (usually /tmp. If pre is not an empty string, it is taken as a prefix for the name of the temporary file.
• tolower(expression)
Returns the string expression with all uppercase characters translated to lowercase.
• toupper(expression)
Does the opposite translation.
• unix_path(name)
Returns name as a standard UNIX path name (for example, with backslashes (\) replaced with forward slashes (/).
When the Enhanced UNIX Compatibility Mode is on (that is, TK_UNIX_FILESYSTEM is set), unix_path() returns the path name name in the virtual file system. See the unix reference page for more information.
• windows_path(name)
Returns name as a Windows path name with all forward slashes (/) replaced with backslashes (\).
When the Enhanced UNIX Compatibility Mode is on (that is, TK_UNIX_FILESYSTEM is set) and name is a relative path that goes through the parent directory (for example, ../dir1/dir2/file1), windows_path() returns the absolute path name of the file.
Environment Variables
TK_UNIX_FILESYSTEM
When this variable is set, the Enhanced UNIX Compatibility Mode is on and the virtual file system is in use. For details on the Enhanced UNIX Compatibility Mode and the virtual file system, see the EUCM reference page.
Availability
MKS Toolkit for Developers
MKS Toolkit for Interoperability
MKS Toolkit for Professional Developers
MKS Toolkit for Enterprise Developers
MKS Toolkit for Enterprise Developers 64-Bit Edition
Integrity Lifecycle Manager
See Also
• Commands: cc