NAME ^

pir.y - Bison specification for the PIR assembly language parser.

DESCRIPTION ^

This file implements the parser for the PIR assembly language. During the parsing phase, data structures are created that represent the input. These data structures are defined in pircompunit.h.

The parser implements strength reduction and constant folding. Strength reduction refers to the selection of instructions that have the same effect as the instruction written by the PIR programmer, but are more efficient. For instance:

 add $P0, $P0, $P1

can be reduced to:

 add $P0, $P1

as $P0 was an IN/OUT operand.

Constant folding refers to the compile-time evaluation of expressions, if possible. For instance:

 add $I0, 10, 20

can be written as:

 set $I0, 30

as we can evaluate this result during compile time. Likewise, conditional branch instructions may become unconditional branch instructions (if the condition evaluates to true during compile time) or it may become a noop (no op) instruction (if the condition evaluates to false during compile time).

CONSTANT FOLDING ^

A binary expression consists of two expressions, separated by a binary operator. An expression can be a target or a literal value. Such a value can be an integer, floating-point or string literal.

In the case that both operands are constants, we can pre-evaluate the result of these constants, effectively preventing any calculation during runtime. For instance:

 $I0 = 42 + 1

can be pre-evaluated as

 $I0 = 43

which will be assembled using the set opcode. Likewise, concatenation of two strings is done during compile time.

FUNCTIONS ^

static constant *fold_i_i(yyscan_t yyscanner, int a, pir_math_operator op, int b)

Evaluates the expression a op b and returns a constant node containing the result value. Both a and b are integer values.

static constant *fold_n_i(yyscan_t yyscanner, double a, pir_math_operator op, int b)

Same as fold_i_i, except a is of type double.

static constant *fold_i_n(yyscan_t yyscanner, int a, pir_math_operator op, double b)

Same as fold_i_i, except b is of type double.

static constant *fold_n_n(yyscan_t yyscanner, double a, pir_math_operator op, double b)

Same as fold_i_i, except that both a and b are of type double.

static constant *fold_s_s(yyscan_t yyscanner, char *a, pir_math_operator op, char *b)

Evaluate the expression a op b, where both a and b are strings. Only the concatenation and comparison operators are implemented; other operators will result in an error.

static int evaluate_i_i(int a, pir_rel_operator op, double b)

Compare a with b according to the relational operator op. Wrapper for evaluate_n_n, which takes arguments of type double.

static int evaluate_n_i(int a, pir_rel_operator op, double b)

Compare a with b according to the relational operator op. Wrapper for evaluate_n_n, which takes arguments of type double.

static int evaluate_i_n(int a, pir_rel_operator op, double b)

Compare a with b according to the relational operator op. Wrapper for evaluate_n_n, which takes arguments of type double.

static int evaluate_n_n(double a, pir_rel_operator op, double b)

Compare a with b according to the relational operator op. op can be <!=>, <==>, <, <=, > or >=.

static int evaluate_s_s(char *a, pir_rel_operator op, char *b)

Compare string a with string b using the operator op. The function uses C's strcmp function. Based on that result, which can be -1 (smaller), 0 (equal) or 1 (larger), a boolean result is returned.

static int evaluate_s(char *const s)

Evaluate a string in boolean context; if the string's length is 0, it's false. If the string equals "0", ".0", "0." or "0.0", it's false. Otherwise, it's true.

static int evaluate_c(constant *const c)

Evaluate a constant node in boolean context; if the constant is numeric, it must be non-zero to be true; if it's a string, evaluate_s is invoked to evaluate the string.

static char *concat_strings(char *a, char *b)

Concatenates two strings into a new buffer; frees all memory of the old strings. The new string is returned.

static int is_parrot_op(lexer_state *const lexer, char const *const spelling)

static void create_if_instr(yyscan_t yyscanner, lexer_state *lexer, int invert, int hasnull, char *const name, char *const label)

Create an if or unless instruction; if invert is non-zero (true), the if instruction is inverted, effectively becoming unless.

If hasnull is non-zero (true), the if instruction becomes if_null; again, if invert is non-zero, the instruction becomes unless_null.

name is the name of the variable that is checked during this instruction

static int check_value(constant *const c, int val)

Check whether the current value of the constant c equals val. For our purposes, it is sufficient to check for integer values (including a check against 1.0 or 0.0). If the values are indeed equal, true is returned, false otherwise. If the constant is not numeric, it returns always false.

static void do_strength_reduction(lexer_state *const lexer)

Implement strength reduction for the math operators add, sub, mul, div and fdiv. If the current instruction is any of these, then the first two operands are checked; if both are targets and are equal, the second operand is removed; this means that the first operand will be an IN/OUT operand. For instance:

 add $I0, $I0, $I1
becomes:

 add $I0, $I1
and

 add $I0, 1
becomes:

 inc $I0


parrot