| 1 |
83 |
davidgb |
/* IfMachine() --- This function implements the IFD & IFND conditional
|
| 2 |
|
|
assembly machine.
|
| 3 |
|
|
version 1.0 made for release TER_2.0 cross assembler 27 Jun 89
|
| 4 |
|
|
*/
|
| 5 |
|
|
|
| 6 |
|
|
#define FALSE_BLOCK 0 /* values for state variable */
|
| 7 |
|
|
#define TRUE_BLOCK 1
|
| 8 |
|
|
#define POP_TEST 2
|
| 9 |
|
|
#define ELSE_TEST 3
|
| 10 |
|
|
#define FALSE 0
|
| 11 |
|
|
#define TRUE 1
|
| 12 |
|
|
|
| 13 |
|
|
void IfMachine(Token)
|
| 14 |
|
|
int Token; /* input token from calling machine */
|
| 15 |
|
|
/* See file as.h for definition (globals) */
|
| 16 |
|
|
{
|
| 17 |
|
|
static int State = TRUE_BLOCK, StackPt = 0, IfStack[MAXIFD];
|
| 18 |
|
|
/* State variable, pointer to "IF stack pointer" and "Stack" */
|
| 19 |
|
|
int Hiatus; /* flag to break out of FSM & resume normal processing */
|
| 20 |
|
|
|
| 21 |
|
|
Hiatus=FALSE; /* infinite loop to operate machine
|
| 22 |
|
|
until time to break out */
|
| 23 |
|
|
do /* test at end */
|
| 24 |
|
|
{
|
| 25 |
|
|
|
| 26 |
|
|
#ifdef DEBUG3
|
| 27 |
|
|
printf("IfMachine state=%u , token=%u\n",State,Token);
|
| 28 |
|
|
#endif
|
| 29 |
|
|
|
| 30 |
|
|
if (State == TRUE_BLOCK) /* a block of statements processed normally */
|
| 31 |
|
|
switch(Token) {
|
| 32 |
|
|
case IF_TRUE:
|
| 33 |
|
|
IfStack[StackPt]=TRUE;
|
| 34 |
|
|
if (++StackPt > MAXIFD) { /* check for over flow */
|
| 35 |
|
|
StackPt = MAXIFD;
|
| 36 |
|
|
error("Error:IFD/IFND nested too deep");
|
| 37 |
|
|
}
|
| 38 |
|
|
/* print_line() will be done in normal processing */
|
| 39 |
|
|
Hiatus = TRUE; /* resume normal line processing */
|
| 40 |
|
|
break;
|
| 41 |
|
|
case IF_FALSE:
|
| 42 |
|
|
IfStack[StackPt]=TRUE;
|
| 43 |
|
|
if (++StackPt > MAXIFD) { /* check for over flow */
|
| 44 |
|
|
StackPt = MAXIFD;
|
| 45 |
|
|
error("Error:IFD/IFND nested too deep");
|
| 46 |
|
|
}
|
| 47 |
|
|
if (Pass == 2 && Lflag && !N_page) /* need to print here */
|
| 48 |
|
|
print_line(); /* cuz will not return to normal */
|
| 49 |
|
|
Token = GetToken(); /* get next line & examine for IF */
|
| 50 |
|
|
State = FALSE_BLOCK; /* change state */
|
| 51 |
|
|
break;
|
| 52 |
|
|
case IF_ELSE:
|
| 53 |
|
|
if (StackPt == 0) /* bad IF nesting */
|
| 54 |
|
|
error("Error: ELSE without IF");
|
| 55 |
|
|
if (Pass == 2 && Lflag && !N_page)
|
| 56 |
|
|
print_line();
|
| 57 |
|
|
Token = GetToken(); /* get next line & examine for IF */
|
| 58 |
|
|
State = FALSE_BLOCK;
|
| 59 |
|
|
break;
|
| 60 |
|
|
case IF_ENDIF:
|
| 61 |
|
|
if (StackPt == 0) /* bad IF nesting */
|
| 62 |
|
|
error("Error: ENDIF without IF");
|
| 63 |
|
|
else
|
| 64 |
|
|
StackPt--; /* popped state must be TRUE */
|
| 65 |
|
|
Hiatus = TRUE;
|
| 66 |
|
|
break;
|
| 67 |
|
|
/* case NORMAL is not implemented as it represents normal line
|
| 68 |
|
|
processing. */
|
| 69 |
|
|
case IF_END: /* file ended with improperly nested IFD */
|
| 70 |
|
|
/* this code can't actually be reached at present
|
| 71 |
|
|
in a TRUE_BLOCK */
|
| 72 |
|
|
fatal("Error: file ended before IFD/IFND/ELSE/ENDIF");
|
| 73 |
|
|
break;
|
| 74 |
|
|
default: /* This code can't be reached at the present.
|
| 75 |
|
|
Logically would happen if EOF but handled
|
| 76 |
|
|
else where */
|
| 77 |
|
|
fatal("Can't get here from there.");
|
| 78 |
|
|
break;
|
| 79 |
|
|
}
|
| 80 |
|
|
else if (State == FALSE_BLOCK) /* statements not processed */
|
| 81 |
|
|
switch(Token) {
|
| 82 |
|
|
case IF_TRUE: /* doesn't make any diff. Just nest IFs */
|
| 83 |
|
|
case IF_FALSE:
|
| 84 |
|
|
IfStack[StackPt]=FALSE;
|
| 85 |
|
|
if (++StackPt > MAXIFD) {
|
| 86 |
|
|
StackPt = MAXIFD;
|
| 87 |
|
|
error("Error:IFD/IFND nested too deep");
|
| 88 |
|
|
}
|
| 89 |
|
|
if (Pass == 2 && Lflag && !N_page)
|
| 90 |
|
|
print_line();
|
| 91 |
|
|
Token = GetToken();
|
| 92 |
|
|
break;
|
| 93 |
|
|
case IF_ELSE:
|
| 94 |
|
|
/* if (Pass == 2 && Lflag && !N_page) */
|
| 95 |
|
|
/* print_line(); */
|
| 96 |
|
|
State = ELSE_TEST;
|
| 97 |
|
|
break;
|
| 98 |
|
|
case IF_ENDIF:
|
| 99 |
|
|
State = POP_TEST;
|
| 100 |
|
|
break;
|
| 101 |
|
|
case IF_END: /* file ended with improperly nested IFD */
|
| 102 |
|
|
fatal("Fatal Error: file ended before last ENDIF");
|
| 103 |
|
|
/* Fatal will exit assembler. Things are too
|
| 104 |
|
|
messed up. Include file handling is else where
|
| 105 |
|
|
and don't want to duplicate here. */
|
| 106 |
|
|
break;
|
| 107 |
|
|
case IF_NORMAL: /* normal line in a FALSE BLOCK */
|
| 108 |
|
|
if (Pass == 2 && Lflag && !N_page)
|
| 109 |
|
|
print_line();
|
| 110 |
|
|
Token = GetToken();
|
| 111 |
|
|
break;
|
| 112 |
|
|
default:
|
| 113 |
|
|
fatal("Fatal Error: file ended before last ENDIF");
|
| 114 |
|
|
/* must be EOF or something else terrible */
|
| 115 |
|
|
break;
|
| 116 |
|
|
}
|
| 117 |
|
|
else if (State == POP_TEST) { /* pop up outside nest state */
|
| 118 |
|
|
if (StackPt == 0) { /* bad IF nesting */
|
| 119 |
|
|
error("Error: ENDIF without IF");
|
| 120 |
|
|
if (Pass == 2 && Lflag && !N_page)
|
| 121 |
|
|
print_line();
|
| 122 |
|
|
State = TRUE;
|
| 123 |
|
|
}
|
| 124 |
|
|
else {
|
| 125 |
|
|
StackPt--; /* pop stack */
|
| 126 |
|
|
if (IfStack[StackPt] == TRUE) { /* back to normal */
|
| 127 |
|
|
/* had to come from FALSE block cuz TRUE block cannot
|
| 128 |
|
|
be inside FALSE block */
|
| 129 |
|
|
if (Pass == 2 && Lflag && !N_page)
|
| 130 |
|
|
print_line();
|
| 131 |
|
|
State = TRUE;
|
| 132 |
|
|
Hiatus = TRUE; /* sleep for normal line processing */
|
| 133 |
|
|
}
|
| 134 |
|
|
else { /* gotta be that stack == FALSE, still inside FALSE nest */
|
| 135 |
|
|
if (Pass == 2 && Lflag && !N_page)
|
| 136 |
|
|
print_line();
|
| 137 |
|
|
State = FALSE;
|
| 138 |
|
|
Token = GetToken();
|
| 139 |
|
|
}
|
| 140 |
|
|
}
|
| 141 |
|
|
}
|
| 142 |
|
|
else if (State == ELSE_TEST) { /* change state */
|
| 143 |
|
|
if (IfStack[StackPt-1] == TRUE) {
|
| 144 |
|
|
State = TRUE_BLOCK;
|
| 145 |
|
|
Hiatus = TRUE;
|
| 146 |
|
|
}
|
| 147 |
|
|
else
|
| 148 |
|
|
State = FALSE_BLOCK;
|
| 149 |
|
|
}
|
| 150 |
|
|
}
|
| 151 |
|
|
while (Hiatus == FALSE); /* loop if not exit */
|
| 152 |
|
|
}
|
| 153 |
|
|
|
| 154 |
|
|
|
| 155 |
|
|
/* GetToken() --- get another line from within False Block and extract token
|
| 156 |
|
|
as would be done in pseudo.c. Returns token id:
|
| 157 |
|
|
IF_TRUE IFD/IFND evaluated to TRUE
|
| 158 |
|
|
IF_FALSE IFD/IFND evaluated to FALSE
|
| 159 |
|
|
IF_ELSE ELSE pseudo op
|
| 160 |
|
|
IF_ENDIF ENDIF pseudo op
|
| 161 |
|
|
IF_END END pseudo op
|
| 162 |
|
|
IF_NORMAL none of the above, perhaps assy code
|
| 163 |
|
|
IF_EOF encountered end of file
|
| 164 |
|
|
This function exists because conditional assembly was added
|
| 165 |
|
|
as pseudo op rather than with key character ("%") and did
|
| 166 |
|
|
not want to disturb original software topology */
|
| 167 |
|
|
|
| 168 |
|
|
int GetToken() /* get another line and find token in it */
|
| 169 |
|
|
{ /* similar to make_pass() except one line at a time */
|
| 170 |
|
|
/* most variables & constants are global */
|
| 171 |
|
|
|
| 172 |
|
|
#ifndef IBM
|
| 173 |
|
|
if (FGETS(Line,MAXBUF-1,Fd) == (char *)NULL)
|
| 174 |
|
|
#else
|
| 175 |
|
|
if (fgets(Line,MAXBUF,Fd) == (char *)NULL)
|
| 176 |
|
|
#endif
|
| 177 |
|
|
return(IF_EOF); /* banged into eof */
|
| 178 |
|
|
Line_num++;
|
| 179 |
|
|
P_force=0;
|
| 180 |
|
|
N_page=0;
|
| 181 |
|
|
if (!parse_line())
|
| 182 |
|
|
return(IF_NORMAL); /* comment line */
|
| 183 |
|
|
if (*Op==EOS) /* skipping over label, probably. */
|
| 184 |
|
|
return(IF_NORMAL); /* strcmp() returns 0 if arg1 is NULL string */
|
| 185 |
|
|
|
| 186 |
|
|
if (strcmp(Op,"ifd")==0)
|
| 187 |
|
|
return(eval_ifd());
|
| 188 |
|
|
else if (strcmp(Op,"ifnd")==0)
|
| 189 |
|
|
return(eval_ifnd());
|
| 190 |
|
|
else if (strcmp(Op,"else")==0)
|
| 191 |
|
|
return(IF_ELSE);
|
| 192 |
|
|
else if (strcmp(Op,"endif")==0)
|
| 193 |
|
|
return(IF_ENDIF);
|
| 194 |
|
|
else if (strcmp(Op,"end")==0)
|
| 195 |
|
|
return(IF_END);
|
| 196 |
|
|
else
|
| 197 |
|
|
return(IF_NORMAL); /* or might be garbage...but who cares?
|
| 198 |
|
|
This is FALSE BLOCK */
|
| 199 |
|
|
}
|
| 200 |
|
|
|
| 201 |
|
|
|
| 202 |
|
|
/*
|
| 203 |
|
|
* eval_ifd() --- evaluate an if define statement for TRUE or FALSE
|
| 204 |
|
|
*/
|
| 205 |
|
|
|
| 206 |
|
|
int
|
| 207 |
|
|
eval_ifd()
|
| 208 |
|
|
{
|
| 209 |
|
|
struct nlist *np; /* symbol structure */
|
| 210 |
|
|
|
| 211 |
|
|
if (*Operand==EOS) {
|
| 212 |
|
|
warn("No symbol for IFD");
|
| 213 |
|
|
return(IF_FALSE); /* nothing to check */
|
| 214 |
|
|
}
|
| 215 |
|
|
if ((np=lookup(Operand)) == NULL)
|
| 216 |
|
|
return(IF_FALSE); /* not defined at all...yet */
|
| 217 |
|
|
else
|
| 218 |
|
|
if(np->def2 == Pass)
|
| 219 |
|
|
return(IF_TRUE); /* defined for this pass */
|
| 220 |
|
|
|
| 221 |
|
|
return(IF_FALSE); /* not defined this pass */
|
| 222 |
|
|
}
|
| 223 |
|
|
|
| 224 |
|
|
/*
|
| 225 |
|
|
* eval_ifnd() --- evaluate an if not define statement for TRUE or FALSE
|
| 226 |
|
|
*/
|
| 227 |
|
|
|
| 228 |
|
|
int
|
| 229 |
|
|
eval_ifnd()
|
| 230 |
|
|
{
|
| 231 |
|
|
struct nlist *np; /* symbol structure */
|
| 232 |
|
|
|
| 233 |
|
|
if (*Operand==EOS) {
|
| 234 |
|
|
warn("No symbol for IFND");
|
| 235 |
|
|
return(IF_TRUE); /* nothing to check */
|
| 236 |
|
|
}
|
| 237 |
|
|
if ((np=lookup(Operand)) == NULL)
|
| 238 |
|
|
return(IF_TRUE); /* not defined at all...yet */
|
| 239 |
|
|
else
|
| 240 |
|
|
if(np->def2 == Pass)
|
| 241 |
|
|
return(IF_FALSE); /* defined for this pass */
|
| 242 |
|
|
|
| 243 |
|
|
return(IF_TRUE); /* not defined this pass */
|
| 244 |
|
|
}
|