Libcompiler

The libcompiler library contains a number of general utility functions that may be used by Flick in any compiler stage. Some of the functionality is only relevant to Flick's front ends (e.g., calls to the C preprocessor), mainly because there is no front end library in which it can be contained. It would be reasonable (and probably trivial) to combine these front end specific routines into a front end library, leaving libcompiler a pure library of general utility functions.

9.1 Errors and Warnings

Some basic functions for reportings errors and warnings:

void panic(const char *format, ...)
Reports an internal error and then exits.
void warn(const char *format, ...)
Prints out a warning message to the user and returns.

Both panic and warn use printf-style arguments.

9.2 Memory and Strings

Memory allocation in Flick is just assumed to work, so the must* allocators either return allocated memory or panic if it fails. Some simple string functions are also provided:

void *mustmalloc(long size)
void *mustcalloc(long size)
void *mustrealloc(void *orig_buf, long new_size)
Memory allocators that always return allocated memory. If no memory is available, it is considered a fatal error, and they internally panic to prevent returning a NULL pointer.
char *muststrdup(const char *str)
Duplicates a string into a freshly allocated buffer, or panics if it cannot allocate the necessary memory.
char *flick_asprintf(const char *fmt, ...)
Like sprintf, however this automatically allocates a sufficient buffer for the resulting string. Like the functions above, this panics if allocation fails.
int flick_strcasecmp(const char *s1, const char *s2)
Case insensitive string comparison; return value is similar to strcmp.
ir_strlit(str)
Convert a string literal for use in an intermediate representation structure. This is just a #define that type casts the argument, helpful for removing warnings/errors about violating constness.

9.3 Files

A number of functions are provided for managing and generating files. All file output is generally done through a set of functions that refer to a globally set file. It is a little restrictive, but at least the file pointer doesn't have to be passed around everywhere. . .

FILE *call_c_preprocessor(const char *filename, const char *flags)
FILE *call_cxx_preprocessor(const char *filename, const char *flags)
Calls the C or C++ preprocessor, respectively, on filename using the given set of preprocessor flags.
FILE *fopen_search(const char *path, const char * const *dir_list, const char *mode, char  **out_path)
Opens a file from a list of source directories. The dir_list argument is a null terminated array of strings representing paths to search for the file indicated by the path argument. If the file is found then it will open it and return the FILE object and set the out_path argument to the directory where the file was found.
void w_set_fh(FILE *out_fh)
Sets the file handle for writing. Each of the following w_* commands output to the file specified by the most recent w_set_fh.
void w_putc(char c)
Writes out the given character.
void w_vprintf(const char *format, va_list vl)
va_list version of w_printf.
void w_printf(const char *format, ...)
Writes out the formatted string.
void w_indent(int indent)
Writes out an indentation of the given size.
void w_i_vprintf(int indent, const char *format, va_list vl)
Indented form of w_vprintf.
void w_i_printf(int indent, const char *format, ...)
Indented form of w_printf.

There are also several functions for manipulating file names, thus allowing for some indirection for different OS file name formats.

char *resuffix(const char *orig, const char *newsuffix)
Returns a new string (filename) with the extension portion of orig changed to newsuffix.
const char *file_part(const char *filename)
Returns a pointer into filename that refers to the file only.
const char *dir_part(const char *filename)
Returns a new string that contains the directory part of filename.
const char *add_file_part(const char *pathname, const char *filename)
Append filename onto pathname intelligently (i.e., adds the `/' if needed).
int absolute_path(const char *filename)
Returns true if filename is an absolute path.
int current_dir(const char *filename)
Returns true if filename refers to the current directory. (Note: This just recognizes `.' at the moment.)
void filename_to_c_id(char *filename)
Convert, in place, a filename to a legal C identifier. This is useful for producing the symbol for an #ifdef in a header file, or for use in distinguishing a function name.

9.4 Command Line Arguments

The command line arguments for a module all follow similar forms so libcompiler provides a flexible infrastructure for dealing with them. It is really quite capable and able to handle flags, strings, numbers, and arrays of these types.

flag_value
A union for holding the value of a flag, either a boolean, integer, or string.
flag_value_seq
Holds a sequence of flag_values so that we can store all instances of a flag on the command line. If a flag can only occur once, or if only the last one is used, then this sequence will be of size one.
flags_in
A structure that describes a single flag. An array of these is constructed and then used to figure out how to parse a command line.
flags_out
Holds the results of a command line parse. The flag values are stored in an array of flag_value_seqs that has the same ordering as the flags_in array. Extra arguments are stored as an array of strings and any errors are indicated by the error slot.
fe_flags
This holds the front end flags after they have been pulled out of the flags_out.

There are also a number of functions for manipulating these structures and the actual arguments.

flags_out parse_args(int argc, char **argv, int flag_count, flags_in *flags)
Parse the given arguments, based on the input flags, into a flagsout and return.
void print_args_usage(const char *progname, int flag_count, flags_in *flgs, const char  *cl_extra, const char *extra)
Print the usage statement for a collection of flags.
void print_args_flags(flags_out res, int flag_count, flags_in *flags)
Debugging function that prints out the parsed flags.
void set_def_flags(flags_in *flgs)
Add the standard flags set to the passed in array.
void std_handler(flags_out out, int flag_count, flags_in *flgs, const char *cl_info,  const char *info)
This will handle version, usage, and errors.
fe_flags front_end_args(int argc, char **argv, const char *info)
Handle the front end args here since we have no front end library.

9.5 Stacks

A simple pointer stack is provided to store pointers when dealing with nested objects and such.
 struct ptr_stack {
         void **ptrs;
         int top;
         int size;
 };

struct ptr_stack *create_ptr_stack()
Allocates and initializes a struct ptr_stack.
void delete_ptr_stack(struct ptr_stack *stack)
Frees a struct ptr_stack.
void push_ptr(struct ptr_stack *stack, void *ptr)
Pushes a pointer onto the stack.
void pop_ptr(struct ptr_stack *stack)
Pops the top pointer off the stack.
void *top_ptr(struct ptr_stack *stack)
Returns the top pointer on the stack.

9.6 Hash Tables

A simple hash table that hashes on a string.
 struct h_entry {
         struct h_entry *next;
         const char *name;
 };
 
 struct h_table {
         int table_size;
         struct h_entry **entries;
 };

struct h_table *create_hash_table(int size)
Allocate and return a hash table of with the given table size.
void delete_hash_table(struct h_table *ht)
Deallocate a hash table.
void add_entry(struct h_table *ht, struct h_entry *he)
Add an entry to the table.
void rem_entry(struct h_table *ht, const char *name)
Remove an entry from the table.
struct h_entry *find_entry(struct h_table *ht, const char *name)
Find and return an entry in the table, if it couldn't be found it returns NULL.

9.7 Linked Lists

A simple doubly linked list implementation is provided for use by other data structures. Simply place the list_node structure at the beginning of another structure definition and then you can add that larger structure to any dl_list.
 struct list_node {
         struct list_node *succ;
         struct list_node *pred;
 };
 
 struct dl_list {
         struct list_node *head; /* points to the head node */
         struct list_node *tail; /* always == 0 */
         struct list_node *tail_pred; /* points to the tail node */
 };

void remove_node(struct list_node *ln)
Removes a node from a list.
void new_list(struct dl_list *list)
Initializes a list structure.
void add_head(struct dl_list *list, struct list_node *ln)
Add a list node to the head of a list.
void add_tail(struct dl_list *list, struct list_node *ln)
Add a list node to the tail of a list.
struct list_node *rem_head(struct dl_list *list)
Remove and return the list node at the head of the list.
struct list_node *rem_tail(struct dl_list *list)
Remove and return the list node at the tail of the list.
int empty_list(struct dl_list *list)
Returns true if the list is empty.
void insert_node(struct list_node *pred, struct list_node *ln)
Insert a node after pred.