Work in progress...

Make expressions work where the % operator isn't (only) at the top
level.
This commit is contained in:
Olaf Seibert 2021-11-14 17:07:21 +01:00
parent 21e9410571
commit c29dc7d7af
2 changed files with 204 additions and 39 deletions

240
extree.c
View File

@ -11,6 +11,7 @@
#include "listing.h"
#include "object.h"
#define DEBUG_REGEXPR 0
/* Diagnostic: print an expression tree. I used this in various
places to help me diagnose parse problems, by putting in calls to
@ -285,7 +286,7 @@ EX_TREE *dup_tree(
case EX_LIT:
res->data.lit = tp->data.lit;
break;
break;
default:
assert(0);
@ -303,12 +304,140 @@ EX_TREE *dup_tree(
return res;
}
/*
* Lift any EX_REG nodes to a higher level in the tree.
*
* There will be at most 1 EX_REG label left in the tree, if any,
* and when it's there it is at the root.
*
* This whole complicated tree manipulation is only there because
* DEC's Macro11 has a global bit per expression to indicate it
* is a register... probably added after the fact without regard
* of the weird expressions it would allow.
*/
EX_TREE *pull_up_reg(
EX_TREE *tp,
int depth)
{
EX_TREE *res;
int nsubtrees;
if (!tp)
return tp;
/* Eliminate multiple levels of EX_REG */
if (tp->type == EX_REG) {
#if DEBUG_REGEXPR
fprintf(stderr, "pull_up_reg: initial EX_REG: ");
print_tree(stderr, tp, 0);
#endif /* DEBUG_REGEXPR */
res = pull_up_reg(tp->data.child.left, depth + 1);
if (res->type != EX_REG) {
res = new_ex_una(EX_REG, res);
}
#if DEBUG_REGEXPR
fprintf(stderr, "pull_up_reg: pulled up EX_REG: ");
print_tree(stderr, res, 0);
#endif /* DEBUG_REGEXPR */
return res;
}
nsubtrees = num_subtrees(tp);
if (nsubtrees > 0) {
EX_TREE *left = tp->data.child.left,
*right = tp->data.child.right,
*evalleft,
*evalright;
int lifted = 0;
#if DEBUG_REGEXPR
fprintf(stderr, "pull_up_reg: before: ");
print_tree(stderr, tp, 0);
#endif /* DEBUG_REGEXPR */
left = pull_up_reg(left, depth + 1);
evalleft = left;
if (left && left->type == EX_REG) {
#if DEBUG_REGEXPR
if (tp->type == EX_REG) {
fprintf(stderr, "pull_up_reg: left->type == EX_REG while tp->type==EX_REG\n");
}
#endif /* DEBUG_REGEXPR */
evalleft = left->data.child.left;
free(left);
lifted++;
}
if (nsubtrees > 1) {
right = pull_up_reg(right, depth + 1);
evalright = right;
if (right && right->type == EX_REG) {
evalright = right->data.child.left;
free(right);
lifted++;
}
} else {
evalright = NULL;
}
res = new_ex_tree(tp->type);
res->data.child.left = evalleft;
res->data.child.right = evalright;
res->cp = tp->cp;
if (lifted) {
res = new_ex_una(EX_REG, res);
#if DEBUG_REGEXPR
fprintf(stderr, "pull_up_reg: after: ");
print_tree(stderr, res, 0);
#endif /* DEBUG_REGEXPR */
}
return res;
}
if (depth > 0 && tp->type == EX_SYM) {
/*
* Temporarily change R0 into %0.
* We only bother to do this in nested expressions, because for
* the common case where R0 is the whole expression this makes
* no sense.
*/
int regno = get_register(tp);
if (regno != NO_REG) {
#if DEBUG_REGEXPR
fprintf(stderr, "pull_up_reg: label `");
print_tree(stderr, tp, 1);
#endif /* DEBUG_REGEXPR */
res = new_ex_lit(regno);
res->cp = tp->cp;
res = new_ex_una(EX_REG, res);
#if DEBUG_REGEXPR
fprintf(stderr, "' to ");
print_tree(stderr, res, 0);
#endif /* DEBUG_REGEXPR */
return res;
}
}
return dup_tree(tp);
}
#define RELTYPE(tp) (((tp)->type == EX_SYM || (tp)->type == EX_TEMP_SYM) && \
(tp)->data.symbol->section->flags & PSECT_REL)
/* evaluate "evaluates" an EX_TREE, ideally trying to produce a
constant value, else a symbol plus an offset. */
EX_TREE *evaluate(
constant value, else a symbol plus an offset.
Leaves the input tree untouched and creates a new tree as result. */
EX_TREE *evaluate_rec(
EX_TREE *tp,
int flags)
{
@ -383,7 +512,7 @@ EX_TREE *evaluate(
case EX_COM:
/* Complement */
tp = evaluate(tp->data.child.left, flags);
tp = evaluate_rec(tp->data.child.left, flags);
if (tp->type == EX_LIT) {
/* Complement the literal */
res = new_ex_lit(~tp->data.lit);
@ -396,7 +525,7 @@ EX_TREE *evaluate(
break;
case EX_NEG:
tp = evaluate(tp->data.child.left, flags);
tp = evaluate_rec(tp->data.child.left, flags);
if (tp->type == EX_LIT) {
/* negate literal */
res = new_ex_lit((unsigned) -(int) tp->data.lit);
@ -416,25 +545,6 @@ EX_TREE *evaluate(
}
break;
case EX_REG:
/* Evaluate as a literal, and create a register label */
{
res = evaluate(tp->data.child.left, flags);
int regno = get_register(res);
if (regno == NO_REG) {
report(NULL, "Register expression out of range.\n");
res = ex_err(res, res->cp);
} else {
EX_TREE *newresult = new_ex_tree(EX_SYM);
newresult->cp = res->cp;
newresult->data.symbol = reg_sym[regno];
res = newresult;
}
}
break;
case EX_ERR:
/* Copy */
res = dup_tree(tp);
@ -445,8 +555,8 @@ EX_TREE *evaluate(
EX_TREE *left,
*right;
left = evaluate(tp->data.child.left, flags);
right = evaluate(tp->data.child.right, flags);
left = evaluate_rec(tp->data.child.left, flags);
right = evaluate_rec(tp->data.child.right, flags);
/* Both literals? Sum them and return result. */
if (left->type == EX_LIT && right->type == EX_LIT) {
@ -521,8 +631,8 @@ EX_TREE *evaluate(
EX_TREE *left,
*right;
left = evaluate(tp->data.child.left, flags);
right = evaluate(tp->data.child.right, flags);
left = evaluate_rec(tp->data.child.left, flags);
right = evaluate_rec(tp->data.child.right, flags);
/* Both literals? Subtract them and return a lit. */
if (left->type == EX_LIT && right->type == EX_LIT) {
@ -597,8 +707,8 @@ EX_TREE *evaluate(
EX_TREE *left,
*right;
left = evaluate(tp->data.child.left, flags);
right = evaluate(tp->data.child.right, flags);
left = evaluate_rec(tp->data.child.left, flags);
right = evaluate_rec(tp->data.child.right, flags);
/* Can only multiply if both are literals */
if (left->type == EX_LIT && right->type == EX_LIT) {
@ -659,8 +769,8 @@ EX_TREE *evaluate(
EX_TREE *left,
*right;
left = evaluate(tp->data.child.left, flags);
right = evaluate(tp->data.child.right, flags);
left = evaluate_rec(tp->data.child.left, flags);
right = evaluate_rec(tp->data.child.right, flags);
/* Can only divide if both are literals */
if (left->type == EX_LIT && right->type == EX_LIT) {
@ -687,8 +797,8 @@ EX_TREE *evaluate(
EX_TREE *left,
*right;
left = evaluate(tp->data.child.left, flags);
right = evaluate(tp->data.child.right, flags);
left = evaluate_rec(tp->data.child.left, flags);
right = evaluate_rec(tp->data.child.right, flags);
/* Operate if both are literals */
if (left->type == EX_LIT && right->type == EX_LIT) {
@ -732,8 +842,8 @@ EX_TREE *evaluate(
EX_TREE *left,
*right;
left = evaluate(tp->data.child.left, flags);
right = evaluate(tp->data.child.right, flags);
left = evaluate_rec(tp->data.child.left, flags);
right = evaluate_rec(tp->data.child.right, flags);
/* Operate if both are literals */
if (left->type == EX_LIT && right->type == EX_LIT) {
@ -777,8 +887,8 @@ EX_TREE *evaluate(
EX_TREE *left,
*right;
left = evaluate(tp->data.child.left, flags);
right = evaluate(tp->data.child.right, flags);
left = evaluate_rec(tp->data.child.left, flags);
right = evaluate_rec(tp->data.child.right, flags);
/* Operate if both are literals */
if (left->type == EX_LIT && right->type == EX_LIT) {
@ -833,6 +943,60 @@ EX_TREE *evaluate(
return res;
}
EX_TREE *evaluate(
EX_TREE *tp,
int flags)
{
EX_TREE *pulled_up,
*res;
int is_register = 0;
#if DEBUG_REGEXPR
fprintf(stderr, "Before pull_up_reg: ");
print_tree(stderr, tp, 0);
#endif /* DEBUG_REGEXPR */
pulled_up = pull_up_reg(tp, 0);
#if DEBUG_REGEXPR
fprintf(stderr, "After pull_up_reg: ");
print_tree(stderr, pulled_up, 0);
#endif /* DEBUG_REGEXPR */
while (pulled_up->type == EX_REG) {
EX_TREE *new = pulled_up->data.child.left;
free(pulled_up);
pulled_up = new;
is_register = 1;
}
res = evaluate_rec(pulled_up, flags);
free_tree(pulled_up);
if (is_register) {
int regno = get_register(res);
if (regno == NO_REG) {
report(NULL, "Register expression out of range.\n");
#if DEBUG_REGEXPR
print_tree(stderr, tp, 0);
print_tree(stderr, res, 0);
#endif /* DEBUG_REGEXPR */
/* TODO: maybe make this a EX_TEMP_SYM? */
res = ex_err(res, res->cp);
} else {
EX_TREE *newresult = new_ex_tree(EX_SYM);
newresult->cp = res->cp;
newresult->data.symbol = reg_sym[regno];
free_tree(res);
res = newresult;
}
}
return res;
}
/* Allocate an EX_TREE */

View File

@ -43,6 +43,7 @@
l14 = %10 ; error: too large (error R), but symbol is still def'd
l15 = %8. ; error: too large (error R), but symbol is still def'd
mov #R2,R2
mov #%2,%2 ; 012702 000002 must be absolute, not reloc!
mov #l1,%2 ; 012702 000001 (idem)
mov #<%1+%2>,%3 ; 012703 000003 (idem)
@ -87,7 +88,7 @@ here: mov #here,%2
l40 = %extrn ; A error; L40 =%******
mov l40,r0 ; U error; code 010000
word r0,wait,%2 ; 0, 1, 2
.word r0,wait,r1+1,wait+2,%4 ; 0, 1, 2, 3, 4
.end