blob: f89c400f93a01b5358f67de8fb2517eb64ed5f73 [file] [log] [blame]
/* %%%%%%%%%%%%%%%%%%%% (c) William Landi 1991 %%%%%%%%%%%%%%%%%%%%%%%%%%%% */
/* Permission to use this code is granted as long as the copyright */
/* notice remains in place. */
/* ================================ scan_line.c ============================ */
/* Contains routines for doing simple parsing of source program (eg. return */
/* label, operator and everthing after the operator). */
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include "stringI.h"
#include "assem.h"
#include "buffer.h"
#include "constants.h"
/* pass_type Which pass the assembler is currently in. Used to */
/* surpress redisplaying pass1 error messages in */
/* pass2. */
enum pass_type {pass1,pass2};
/* ----------------------------- UPPER (local) ----------------------------- */
/* If CH is a lower case letter, return the upper case version, otherwise */
/* Return the character. */
char UPPER(CH)
char CH; /* Character to convert to upper case (if needed). */
{
if ((CH >= 'a') && (CH <= 'z')) return (CH - 'a' + 'A');
else return CH;
}
/* ------------------------------ IS_ALPHA_NUM ----------------------------- */
/* True if CH is a capital letter or a digit. Otherwise false. */
int IS_ALPHA_NUM(CH)
char CH; /* Character in question. */
{
CH = UPPER(CH);
return ( ((CH >= 'A') && (CH <= 'Z')) || ((CH >= '0') && (CH <= '9')) );
}
/* ------------------------------ IS_BLANK_OR_TAB -------------------------- */
/* True if CH is a blank or a tab, otherwise false. */
int IS_BLANK_OR_TAB(CH)
char CH; /* Character in question. */
{
return ((CH == ' ' /* Blank */) || (CH == ' ' /* TAB */));
}
/* ----------------------------- eoln -------------------------------------- */
/* true if CH is the End Of LiNe character, otherwise false. */
int eoln(CH)
char CH; /* Character in question. */
{
return (CH == '\0');
}
/* -------------------------------- GET_LABEL ------------------------------ */
/* Get a SIC/XE Label (Letter followed by zero to seven letters or digits). */
/* Return it in LABEL. Get it from INPUT starting from NEXT_CHAR. */
void GET_LABEL (LABEL,INPUT,NEXT_CHAR,PASS)
char *LABEL; /* Where to put the label if found. */
char *INPUT; /* String to get the label from. */
enum pass_type PASS; /* pass1 = buffers error messages in ERROR_REC_BUF*/
/* pass2 = don't buffer error messages. */
char **NEXT_CHAR; /* where to start looking for the label in INPUT */
{
if ((UPPER(**NEXT_CHAR) >= 'A') && (UPPER(**NEXT_CHAR) <= 'Z')) {
/* GET LABEL */
int LABEL_LEN = 1;
(*NEXT_CHAR) ++;
while (IS_ALPHA_NUM(**NEXT_CHAR) && (!eoln(**NEXT_CHAR))) {
LABEL_LEN ++;
(*NEXT_CHAR) ++;
};
if (LABEL_LEN > LABEL_SIZE_1) {
if (PASS == pass1) {
char TEMP;
char *ERROR_MSG;
TEMP = INPUT[LABEL_LEN];
INPUT[LABEL_LEN] = '\0';
ERROR_MSG = (char *) malloc((unsigned int)
(80+ ((int) log10((double) LABEL_SIZE_1)) +strlen(INPUT)));
(void) sprintf(ERROR_MSG,
"eERROR[1]: Label '%s' is too long (MAX %d characters).",
INPUT,LABEL_SIZE_1);
ADD_TO_END_OF_BUFFER(&ERROR_REC_BUF,ERROR_MSG);
free(ERROR_MSG);
INPUT[LABEL_LEN] = TEMP;
};
/* ------------------- truncate to 8 characters. */
LABEL_LEN = LABEL_SIZE_1;
};
(void) strncpy(LABEL,INPUT,LABEL_LEN);
LABEL[LABEL_LEN] = '\0';
/* End GET LABEL */
} else {
/* ---------- Object Starting at NEXT_CHAR can not possible be a label */
/* Return the empty string ("") */
LABEL[0] = '\0';
}
}
/* ------------------------- GET_OPCODE_STR -------------------------------- */
/* Get a SIC/XE OPERAND (string of letters, not more than 8).Return it in */
/* OPCODE. Get it from INPUT starting from NEXT_CHAR. */
void GET_OPCODE_STR (OPCODE,NEXT_CHAR,PASS,STREAM)
char *OPCODE; /* Where to put the opcode that was found. */
enum pass_type PASS; /* pass1 = print error messages; pass2 = don't*/
/* print error messages. */
char **NEXT_CHAR; /* Where to look for the OPERAND */
FILE *STREAM; /* Stream to output error messages to. */
{
char *START_OF_OPCODE;
START_OF_OPCODE = *NEXT_CHAR;
if ((UPPER(**NEXT_CHAR) >= 'A') && (UPPER(**NEXT_CHAR) <= 'Z')) {
int OP_LEN = 1;
(*NEXT_CHAR) ++;
while (((UPPER(**NEXT_CHAR) >= 'A') && (UPPER(**NEXT_CHAR) <= 'Z'))
&& (!eoln(**NEXT_CHAR))) {
OP_LEN ++;
(*NEXT_CHAR) ++;
};
if (OP_LEN > LABEL_SIZE_1) {
/* -------------- (maybe) print error message, and truncate to 8 characters. */
if (PASS == pass1) {
char TEMP;
TEMP = START_OF_OPCODE[OP_LEN];
START_OF_OPCODE[OP_LEN] = '\0';
(void) fprintf(STREAM,
"eERROR[3]: OpCode field '%s' is too long. Truncating to %d charaters.\n"
,START_OF_OPCODE,LABEL_SIZE_1);
START_OF_OPCODE[OP_LEN] = TEMP;
};
OP_LEN = LABEL_SIZE_1;
};
(void) strncpy(OPCODE,START_OF_OPCODE,OP_LEN);
OPCODE[OP_LEN] = '\0';
} else {
OPCODE[0] = 0;
}
}
/* ---------------------------- SCAN_LINE ---------------------------------- */
/* Reads in a sourse program line and does simple parsing. */
void SCAN_LINE (LOCATION_COUNTER,INPUT_LINE,LABEL,EXTENDED,OPERATOR,
REST,PASS,STREAM,INPUT_STREAM)
int LOCATION_COUNTER; /* SIC/XE location counter at start of line*/
char **INPUT_LINE; /* Where to return the source line */
char *LABEL; /* Where to return the label if one exists */
int *EXTENDED; /* Boolean: Is there a '+' before the */
/* operator. i.e. is this extended format*/
char *OPERATOR; /* Where to return the operator. */
char **REST; /* Where to return everything after the */
/* operator. Ignoring leading white-space*/
enum pass_type PASS; /* pass1 = do print error messages and */
/* source; pass2 = do not print error */
/* messages. */
FILE *STREAM; /* Stream for outputing error messages and */
/* the source code */
FILE *INPUT_STREAM; /* Where to get the source line from */
{
char *CH;
GET_LINE(INPUT_LINE,INPUT_STREAM);
(*REST) = (*INPUT_LINE);
if (PASS == pass1)
(void) fprintf(STREAM,"p%d %s\n",LOCATION_COUNTER,*REST);
CH = *REST;
if (*CH != '.') {
/* ---------------------- Not a comment line */
GET_LABEL(LABEL,*REST,&CH,PASS);
OUTPUT_BUFFER(&ERROR_REC_BUF,STREAM,1);
/* ---------------------- Must be white space after a operator. */
if (!IS_BLANK_OR_TAB(*CH) && !eoln(*CH)) {
if (PASS == pass1)
(void) fprintf(STREAM,
"eERROR[2]: Illegal LABEL/OPCODE seperater('%c') expected <tab> or <blank>.\n",
*CH);
CH ++;
};
/* ---------------------- remove white space characters */
while (IS_BLANK_OR_TAB(*CH) && !eoln(*CH)) CH ++;
if (*CH == '+') {
CH ++;
(*EXTENDED) = 1;
} else (*EXTENDED) = 0;
GET_OPCODE_STR(OPERATOR,&CH,PASS,STREAM);
if ((*EXTENDED == 1) && !strcmp(OPERATOR,"") && (PASS == pass1))
(void) fprintf(STREAM,"eERROR[5]: Expected an OPCODE after the '+'.\n");
/* ---------------------- Must be white space after a label. */
if (!IS_BLANK_OR_TAB(*CH) && !eoln(*CH)) {
if (PASS == pass1)
(void) fprintf(STREAM,
"eERROR[4]: Illegal OPCODE/OPERANDS seperater('%c') expected TAB or BLANK.\n",
*CH);
CH ++;
};
/* ---------------------- remove white space characters */
while (IS_BLANK_OR_TAB(*CH) && !eoln(*CH)) CH ++;
(*REST) = CH;
} else {
/* ---------------------- comment line */
LABEL[0] = '\0';
(*EXTENDED) = 0;
OPERATOR[0] = '\0';
}
}