/* IfMachine() --- This function implements the IFD & IFND conditional
|
/* IfMachine() --- This function implements the IFD & IFND conditional
|
assembly machine.
|
assembly machine.
|
version 1.0 made for release TER_2.0 cross assembler 27 Jun 89
|
version 1.0 made for release TER_2.0 cross assembler 27 Jun 89
|
*/
|
*/
|
|
|
#define FALSE_BLOCK 0 /* values for state variable */
|
#define FALSE_BLOCK 0 /* values for state variable */
|
#define TRUE_BLOCK 1
|
#define TRUE_BLOCK 1
|
#define POP_TEST 2
|
#define POP_TEST 2
|
#define ELSE_TEST 3
|
#define ELSE_TEST 3
|
#define FALSE 0
|
#define FALSE 0
|
#define TRUE 1
|
#define TRUE 1
|
|
|
void IfMachine(Token)
|
void IfMachine(Token)
|
int Token; /* input token from calling machine */
|
int Token; /* input token from calling machine */
|
/* See file as.h for definition (globals) */
|
/* See file as.h for definition (globals) */
|
{
|
{
|
static int State = TRUE_BLOCK, StackPt = 0, IfStack[MAXIFD];
|
static int State = TRUE_BLOCK, StackPt = 0, IfStack[MAXIFD];
|
/* State variable, pointer to "IF stack pointer" and "Stack" */
|
/* State variable, pointer to "IF stack pointer" and "Stack" */
|
int Hiatus; /* flag to break out of FSM & resume normal processing */
|
int Hiatus; /* flag to break out of FSM & resume normal processing */
|
|
|
Hiatus=FALSE; /* infinite loop to operate machine
|
Hiatus=FALSE; /* infinite loop to operate machine
|
until time to break out */
|
until time to break out */
|
do /* test at end */
|
do /* test at end */
|
{
|
{
|
|
|
#ifdef DEBUG3
|
#ifdef DEBUG3
|
printf("IfMachine state=%u , token=%u\n",State,Token);
|
printf("IfMachine state=%u , token=%u\n",State,Token);
|
#endif
|
#endif
|
|
|
if (State == TRUE_BLOCK) /* a block of statements processed normally */
|
if (State == TRUE_BLOCK) /* a block of statements processed normally */
|
switch(Token) {
|
switch(Token) {
|
case IF_TRUE:
|
case IF_TRUE:
|
IfStack[StackPt]=TRUE;
|
IfStack[StackPt]=TRUE;
|
if (++StackPt > MAXIFD) { /* check for over flow */
|
if (++StackPt > MAXIFD) { /* check for over flow */
|
StackPt = MAXIFD;
|
StackPt = MAXIFD;
|
error("Error:IFD/IFND nested too deep");
|
error("Error:IFD/IFND nested too deep");
|
}
|
}
|
/* print_line() will be done in normal processing */
|
/* print_line() will be done in normal processing */
|
Hiatus = TRUE; /* resume normal line processing */
|
Hiatus = TRUE; /* resume normal line processing */
|
break;
|
break;
|
case IF_FALSE:
|
case IF_FALSE:
|
IfStack[StackPt]=TRUE;
|
IfStack[StackPt]=TRUE;
|
if (++StackPt > MAXIFD) { /* check for over flow */
|
if (++StackPt > MAXIFD) { /* check for over flow */
|
StackPt = MAXIFD;
|
StackPt = MAXIFD;
|
error("Error:IFD/IFND nested too deep");
|
error("Error:IFD/IFND nested too deep");
|
}
|
}
|
if (Pass == 2 && Lflag && !N_page) /* need to print here */
|
if (Pass == 2 && Lflag && !N_page) /* need to print here */
|
print_line(); /* cuz will not return to normal */
|
print_line(); /* cuz will not return to normal */
|
Token = GetToken(); /* get next line & examine for IF */
|
Token = GetToken(); /* get next line & examine for IF */
|
State = FALSE_BLOCK; /* change state */
|
State = FALSE_BLOCK; /* change state */
|
break;
|
break;
|
case IF_ELSE:
|
case IF_ELSE:
|
if (StackPt == 0) /* bad IF nesting */
|
if (StackPt == 0) /* bad IF nesting */
|
error("Error: ELSE without IF");
|
error("Error: ELSE without IF");
|
if (Pass == 2 && Lflag && !N_page)
|
if (Pass == 2 && Lflag && !N_page)
|
print_line();
|
print_line();
|
Token = GetToken(); /* get next line & examine for IF */
|
Token = GetToken(); /* get next line & examine for IF */
|
State = FALSE_BLOCK;
|
State = FALSE_BLOCK;
|
break;
|
break;
|
case IF_ENDIF:
|
case IF_ENDIF:
|
if (StackPt == 0) /* bad IF nesting */
|
if (StackPt == 0) /* bad IF nesting */
|
error("Error: ENDIF without IF");
|
error("Error: ENDIF without IF");
|
else
|
else
|
StackPt--; /* popped state must be TRUE */
|
StackPt--; /* popped state must be TRUE */
|
Hiatus = TRUE;
|
Hiatus = TRUE;
|
break;
|
break;
|
/* case NORMAL is not implemented as it represents normal line
|
/* case NORMAL is not implemented as it represents normal line
|
processing. */
|
processing. */
|
case IF_END: /* file ended with improperly nested IFD */
|
case IF_END: /* file ended with improperly nested IFD */
|
/* this code can't actually be reached at present
|
/* this code can't actually be reached at present
|
in a TRUE_BLOCK */
|
in a TRUE_BLOCK */
|
fatal("Error: file ended before IFD/IFND/ELSE/ENDIF");
|
fatal("Error: file ended before IFD/IFND/ELSE/ENDIF");
|
break;
|
break;
|
default: /* This code can't be reached at the present.
|
default: /* This code can't be reached at the present.
|
Logically would happen if EOF but handled
|
Logically would happen if EOF but handled
|
else where */
|
else where */
|
fatal("Can't get here from there.");
|
fatal("Can't get here from there.");
|
break;
|
break;
|
}
|
}
|
else if (State == FALSE_BLOCK) /* statements not processed */
|
else if (State == FALSE_BLOCK) /* statements not processed */
|
switch(Token) {
|
switch(Token) {
|
case IF_TRUE: /* doesn't make any diff. Just nest IFs */
|
case IF_TRUE: /* doesn't make any diff. Just nest IFs */
|
case IF_FALSE:
|
case IF_FALSE:
|
IfStack[StackPt]=FALSE;
|
IfStack[StackPt]=FALSE;
|
if (++StackPt > MAXIFD) {
|
if (++StackPt > MAXIFD) {
|
StackPt = MAXIFD;
|
StackPt = MAXIFD;
|
error("Error:IFD/IFND nested too deep");
|
error("Error:IFD/IFND nested too deep");
|
}
|
}
|
if (Pass == 2 && Lflag && !N_page)
|
if (Pass == 2 && Lflag && !N_page)
|
print_line();
|
print_line();
|
Token = GetToken();
|
Token = GetToken();
|
break;
|
break;
|
case IF_ELSE:
|
case IF_ELSE:
|
/* if (Pass == 2 && Lflag && !N_page) */
|
/* if (Pass == 2 && Lflag && !N_page) */
|
/* print_line(); */
|
/* print_line(); */
|
State = ELSE_TEST;
|
State = ELSE_TEST;
|
break;
|
break;
|
case IF_ENDIF:
|
case IF_ENDIF:
|
State = POP_TEST;
|
State = POP_TEST;
|
break;
|
break;
|
case IF_END: /* file ended with improperly nested IFD */
|
case IF_END: /* file ended with improperly nested IFD */
|
fatal("Fatal Error: file ended before last ENDIF");
|
fatal("Fatal Error: file ended before last ENDIF");
|
/* Fatal will exit assembler. Things are too
|
/* Fatal will exit assembler. Things are too
|
messed up. Include file handling is else where
|
messed up. Include file handling is else where
|
and don't want to duplicate here. */
|
and don't want to duplicate here. */
|
break;
|
break;
|
case IF_NORMAL: /* normal line in a FALSE BLOCK */
|
case IF_NORMAL: /* normal line in a FALSE BLOCK */
|
if (Pass == 2 && Lflag && !N_page)
|
if (Pass == 2 && Lflag && !N_page)
|
print_line();
|
print_line();
|
Token = GetToken();
|
Token = GetToken();
|
break;
|
break;
|
default:
|
default:
|
fatal("Fatal Error: file ended before last ENDIF");
|
fatal("Fatal Error: file ended before last ENDIF");
|
/* must be EOF or something else terrible */
|
/* must be EOF or something else terrible */
|
break;
|
break;
|
}
|
}
|
else if (State == POP_TEST) { /* pop up outside nest state */
|
else if (State == POP_TEST) { /* pop up outside nest state */
|
if (StackPt == 0) { /* bad IF nesting */
|
if (StackPt == 0) { /* bad IF nesting */
|
error("Error: ENDIF without IF");
|
error("Error: ENDIF without IF");
|
if (Pass == 2 && Lflag && !N_page)
|
if (Pass == 2 && Lflag && !N_page)
|
print_line();
|
print_line();
|
State = TRUE;
|
State = TRUE;
|
}
|
}
|
else {
|
else {
|
StackPt--; /* pop stack */
|
StackPt--; /* pop stack */
|
if (IfStack[StackPt] == TRUE) { /* back to normal */
|
if (IfStack[StackPt] == TRUE) { /* back to normal */
|
/* had to come from FALSE block cuz TRUE block cannot
|
/* had to come from FALSE block cuz TRUE block cannot
|
be inside FALSE block */
|
be inside FALSE block */
|
if (Pass == 2 && Lflag && !N_page)
|
if (Pass == 2 && Lflag && !N_page)
|
print_line();
|
print_line();
|
State = TRUE;
|
State = TRUE;
|
Hiatus = TRUE; /* sleep for normal line processing */
|
Hiatus = TRUE; /* sleep for normal line processing */
|
}
|
}
|
else { /* gotta be that stack == FALSE, still inside FALSE nest */
|
else { /* gotta be that stack == FALSE, still inside FALSE nest */
|
if (Pass == 2 && Lflag && !N_page)
|
if (Pass == 2 && Lflag && !N_page)
|
print_line();
|
print_line();
|
State = FALSE;
|
State = FALSE;
|
Token = GetToken();
|
Token = GetToken();
|
}
|
}
|
}
|
}
|
}
|
}
|
else if (State == ELSE_TEST) { /* change state */
|
else if (State == ELSE_TEST) { /* change state */
|
if (IfStack[StackPt-1] == TRUE) {
|
if (IfStack[StackPt-1] == TRUE) {
|
State = TRUE_BLOCK;
|
State = TRUE_BLOCK;
|
Hiatus = TRUE;
|
Hiatus = TRUE;
|
}
|
}
|
else
|
else
|
State = FALSE_BLOCK;
|
State = FALSE_BLOCK;
|
}
|
}
|
}
|
}
|
while (Hiatus == FALSE); /* loop if not exit */
|
while (Hiatus == FALSE); /* loop if not exit */
|
}
|
}
|
|
|
|
|
/* GetToken() --- get another line from within False Block and extract token
|
/* GetToken() --- get another line from within False Block and extract token
|
as would be done in pseudo.c. Returns token id:
|
as would be done in pseudo.c. Returns token id:
|
IF_TRUE IFD/IFND evaluated to TRUE
|
IF_TRUE IFD/IFND evaluated to TRUE
|
IF_FALSE IFD/IFND evaluated to FALSE
|
IF_FALSE IFD/IFND evaluated to FALSE
|
IF_ELSE ELSE pseudo op
|
IF_ELSE ELSE pseudo op
|
IF_ENDIF ENDIF pseudo op
|
IF_ENDIF ENDIF pseudo op
|
IF_END END pseudo op
|
IF_END END pseudo op
|
IF_NORMAL none of the above, perhaps assy code
|
IF_NORMAL none of the above, perhaps assy code
|
IF_EOF encountered end of file
|
IF_EOF encountered end of file
|
This function exists because conditional assembly was added
|
This function exists because conditional assembly was added
|
as pseudo op rather than with key character ("%") and did
|
as pseudo op rather than with key character ("%") and did
|
not want to disturb original software topology */
|
not want to disturb original software topology */
|
|
|
int GetToken() /* get another line and find token in it */
|
int GetToken() /* get another line and find token in it */
|
{ /* similar to make_pass() except one line at a time */
|
{ /* similar to make_pass() except one line at a time */
|
/* most variables & constants are global */
|
/* most variables & constants are global */
|
|
|
struct nlist *lookup();
|
|
|
|
#ifndef IBM
|
#ifndef IBM
|
if (FGETS(Line,MAXBUF-1,Fd) == (char *)NULL)
|
if (FGETS(Line,MAXBUF-1,Fd) == (char *)NULL)
|
#else
|
#else
|
if (fgets(Line,MAXBUF,Fd) == (char *)NULL)
|
if (fgets(Line,MAXBUF,Fd) == (char *)NULL)
|
#endif
|
#endif
|
return(IF_EOF); /* banged into eof */
|
return(IF_EOF); /* banged into eof */
|
Line_num++;
|
Line_num++;
|
P_force=0;
|
P_force=0;
|
N_page=0;
|
N_page=0;
|
if (!parse_line())
|
if (!parse_line())
|
return(IF_NORMAL); /* comment line */
|
return(IF_NORMAL); /* comment line */
|
if (*Op==EOS) /* skipping over label, probably. */
|
if (*Op==EOS) /* skipping over label, probably. */
|
return(IF_NORMAL); /* strcmp() returns 0 if arg1 is NULL string */
|
return(IF_NORMAL); /* strcmp() returns 0 if arg1 is NULL string */
|
|
|
if (strcmp(Op,"ifd")==0)
|
if (strcmp(Op,"ifd")==0)
|
return(eval_ifd());
|
return(eval_ifd());
|
else if (strcmp(Op,"ifnd")==0)
|
else if (strcmp(Op,"ifnd")==0)
|
return(eval_ifnd());
|
return(eval_ifnd());
|
else if (strcmp(Op,"else")==0)
|
else if (strcmp(Op,"else")==0)
|
return(IF_ELSE);
|
return(IF_ELSE);
|
else if (strcmp(Op,"endif")==0)
|
else if (strcmp(Op,"endif")==0)
|
return(IF_ENDIF);
|
return(IF_ENDIF);
|
else if (strcmp(Op,"end")==0)
|
else if (strcmp(Op,"end")==0)
|
return(IF_END);
|
return(IF_END);
|
else
|
else
|
return(IF_NORMAL); /* or might be garbage...but who cares?
|
return(IF_NORMAL); /* or might be garbage...but who cares?
|
This is FALSE BLOCK */
|
This is FALSE BLOCK */
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* eval_ifd() --- evaluate an if define statement for TRUE or FALSE
|
* eval_ifd() --- evaluate an if define statement for TRUE or FALSE
|
*/
|
*/
|
|
|
int
|
int
|
eval_ifd()
|
eval_ifd()
|
{
|
{
|
struct nlist *np; /* symbol structure */
|
struct nlist *np; /* symbol structure */
|
|
|
if (*Operand==EOS) {
|
if (*Operand==EOS) {
|
warn("No symbol for IFD");
|
warn("No symbol for IFD");
|
return(IF_FALSE); /* nothing to check */
|
return(IF_FALSE); /* nothing to check */
|
}
|
}
|
if ((np=lookup(Operand)) == NULL)
|
if ((np=lookup(Operand)) == NULL)
|
return(IF_FALSE); /* not defined at all...yet */
|
return(IF_FALSE); /* not defined at all...yet */
|
else
|
else
|
if(np->def2 == Pass)
|
if(np->def2 == Pass)
|
return(IF_TRUE); /* defined for this pass */
|
return(IF_TRUE); /* defined for this pass */
|
|
|
return(IF_FALSE); /* not defined this pass */
|
return(IF_FALSE); /* not defined this pass */
|
}
|
}
|
|
|
/*
|
/*
|
* eval_ifnd() --- evaluate an if not define statement for TRUE or FALSE
|
* eval_ifnd() --- evaluate an if not define statement for TRUE or FALSE
|
*/
|
*/
|
|
|
int
|
int
|
eval_ifnd()
|
eval_ifnd()
|
{
|
{
|
struct nlist *np; /* symbol structure */
|
struct nlist *np; /* symbol structure */
|
|
|
if (*Operand==EOS) {
|
if (*Operand==EOS) {
|
warn("No symbol for IFND");
|
warn("No symbol for IFND");
|
return(IF_TRUE); /* nothing to check */
|
return(IF_TRUE); /* nothing to check */
|
}
|
}
|
if ((np=lookup(Operand)) == NULL)
|
if ((np=lookup(Operand)) == NULL)
|
return(IF_TRUE); /* not defined at all...yet */
|
return(IF_TRUE); /* not defined at all...yet */
|
else
|
else
|
if(np->def2 == Pass)
|
if(np->def2 == Pass)
|
return(IF_FALSE); /* defined for this pass */
|
return(IF_FALSE); /* defined for this pass */
|
|
|
return(IF_TRUE); /* not defined this pass */
|
return(IF_TRUE); /* not defined this pass */
|
}
|
}
|
|
|