pir.l - implementation of the lexical analyzer of the PIR assembly language.


This file implements the lexical analyzer of the PIR assembly language. The macro layer is implemented here as well. Heredocs are processed by a different preprocessor.


Helper functions for macro expansion. These function are only used by the lexer, so keep them local to this file.

void init_scanner_state(yyscan_t yyscanner)

Initializes yyscanner to the SPECIALSTART state, which can then decide whether to scan PASM or PIR tokens.

static macro_table *peek_macro_table(lexer_state *const lexer)

Return the top of the macro_table stack; this is the currently active macro_table object.

static char *munge_id(char const *const id, lexer_state *const lexer)

Generate an identifier based on a macro label or local expansion.

A label expansion looks like ".$<LABEL>", from which a label identifier is generated, formatted as: "$macro_<MACRO>_<LABEL>_<SCOPE>".

In this format, MACRO refers to the macro name of the macro in which the .macro_local or .macro_label was defined; LABEL refers to the runtime value of the label or local variable (this can be a macro's argument's value). SCOPE refers to the unique scope ID of this macro expansion.

static macro_table *pop_macro_table(lexer_state *const lexer)

Pop off the current macro symbol table from the macro symbol table stack and return it.

static void push_macro_table(lexer_state *const lexer, macro_table *const table)

Push macro_table table onto the macro scope stack. Any attempt to find a macro definition will start in table. If not found, the stack will be walked down (recursing into older entries).

static void update_unique_id(lexer_state *const lexer)

Update the unique ID generator; the number of characters that the new number is taking in a string is recalculated, as the unique IDs are used in string context.

static void expand(yyscan_t yyscanner, macro_def *const macro, list *args, lexer_state *const lexer)

Expand the specified macro (or constant). The current yy_buffer_state is saved, as well as the current scope ID (for macro expansions; each expansion has its own unique scope ID); as well as the current line number. The macro_table, which defines the macro parameters/arguments, gets a reference to the macro definition that is being expanded; that's the thismacro field of the macro_table structure.

An argument count check is done to make sure there's exactly enough arguments for the defined parameters. Then, the macro definition's body (a string buffer) is scanned (instead of the file that we were scanning).

The function returns the body of the macro being expanded.

void *yyalloc(size_t bytes, yyscan_t yyscanner)

Allocate bytes of memory; the yyscanner argument is not used.

void *yyrealloc(void *ptr, size_t bytes, yyscan_t yyscanner)

Reallocate memory pointed to by ptr. The new memory region is bytes in size; the yyscanner argument is not used.

void yyfree(void *ptr, yyscan_t yyscanner)

Free memory pointed to by ptr. The yyscanner argument is not used, but part of the signature as it is a Flex-generated function.