parrotcode: Bison specification for the PIR assembly language parser. | |
Contents | Compilers |
pir.y - Bison specification for the PIR assembly language parser.
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).
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.
static constant *fold_i_i(yyscan_t yyscanner, int a, pir_math_operator op, int b)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
static int evaluate_c(constant *const c)
evaluate_s
is invoked to evaluate the string.static char *concat_strings(char *a, char *b)
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)
if
or unless
instruction; if invert
is non-zero (true), the if
instruction is inverted, effectively becoming unless
.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 instructionstatic int check_value(constant *const c, int val)
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)
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
add $I0, $I1
add $I0, 1
inc $I0
|