4coder-non-source/test_data/lots_of_files/assembler.c

388 lines
9.3 KiB
C

/* Assembler code fragment for LC-2K */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAXLINELENGTH 1000
int readAndParse(FILE *, char *, char *, char *, char *, char *);
int isNumber(char *, int *);
typedef struct{
char *word;
unsigned int hash;
int line_number;
} Label;
typedef struct{
char *word_space;
char *word_cursor;
Label *labels;
int count;
int max;
} Table;
char *
copy_advance(char *dest, char *src){
while (*dest++ = *src++);
return(dest);
}
int
get_hash(char *string){
unsigned int x, c;
x = 5236;
while (c = *string++){
x += c + (x << 5) + (x << 1);
}
return(x);
}
int
add_label(Table *table, char *string, int line_number){
int r;
Label l, *ls;
int max;
unsigned int index;
r = 0;
max = table->max;
ls = table->labels;
l.word = table->word_cursor;
table->word_cursor = copy_advance(table->word_cursor, string);
l.hash = get_hash(string);
l.line_number = line_number;
index = l.hash % max;
while (ls[index].word){
if (ls[index].hash == l.hash){
if (strcmp(ls[index].word, l.word) == 0){
r = 1;
break;
}
}
index = (index + 1) % max;
}
if (r == 0) ls[index] = l;
++table->count;
return(r);
}
int
find_label(Table *table, char *string, int *line_number){
int r;
Label l, *ls;
int max;
unsigned int hash,index;
r = 0;
max = table->max;
ls = table->labels;
hash = get_hash(string);
index = hash % max;
while (ls[index].word){
if (ls[index].hash == hash){
if (strcmp(ls[index].word, string) == 0){
r = 1;
*line_number = ls[index].line_number;
break;
}
}
index = (index + 1) % max;
}
return(r);
}
#define OP_FILL -1
#define OP_ADD 0
#define OP_NAND 1
#define OP_LW 2
#define OP_SW 3
#define OP_BEQ 4
#define OP_JALR 5
#define OP_HALT 6
#define OP_NOOP 7
#define MIN16S -32768
#define MAX16S 32767
int
encode_insanity(FILE *outFilePtr, int o, int a, int b, int c){
int ins, r;
r = 0;
if (o == OP_FILL){
r = (b != 0 || c != 0);
}
else{
r = (a < 0 || a > 7 || b < 0 || b > 7);
if (!r){
switch (o){
case OP_ADD: case OP_NAND:
r = (c < 0 || c > 7); break;
case OP_LW: case OP_SW:
case OP_BEQ: case OP_JALR:
r = (c < MIN16S || c > MAX16S); break;
case OP_HALT: case OP_NOOP:
r = (a != 0 || b != 0 || c != 0); break;
default: r = 1; break;
}
}
}
if (!r){
if (o == OP_FILL){
ins = a;
}
else{
ins = 0;
ins |= (o << 22);
ins |= (a << 19);
ins |= (b << 16);
ins |= 0xFFFF & (c);
}
fprintf(outFilePtr, "%d\n", ins);
}
return(r);
}
int
main(int argc, char *argv[])
{
Table table;
char *inFileString, *outFileString;
FILE *inFilePtr, *outFilePtr;
char label[MAXLINELENGTH], opcode[MAXLINELENGTH], arg0[MAXLINELENGTH],
arg1[MAXLINELENGTH], arg2[MAXLINELENGTH];
int max_instructions;
int line_number;
int i;
int o,a,b,c;
if (argc != 3) {
printf("error: usage: %s <assembly-code-file> <machine-code-file>\n",
argv[0]);
exit(1);
}
inFileString = argv[1];
outFileString = argv[2];
inFilePtr = fopen(inFileString, "r");
if (inFilePtr == NULL) {
printf("error in opening %s\n", inFileString);
exit(1);
}
outFilePtr = fopen(outFileString, "w");
if (outFilePtr == NULL) {
printf("error in opening %s\n", outFileString);
exit(1);
}
fseek(inFilePtr, 0, SEEK_END);
max_instructions = ftell(inFilePtr);
fseek(inFilePtr, 0, SEEK_SET);
max_instructions >>= 2;
table.max = max_instructions * 3 / 2;
table.labels = (Label*)malloc(sizeof(Label)*table.max);
table.count = 0;
table.word_space = table.word_cursor = (char*)malloc((max_instructions << 2) + max_instructions);
memset(table.labels, 0, sizeof(Label)*table.max);
line_number = 0;
while (readAndParse(inFilePtr, label, opcode, arg0, arg1, arg2)){
if (*label != 0){
if (add_label(&table, label, line_number)){
printf("error two labels of same name: %s\n", label);
exit(1);
}
}
++line_number;
}
rewind(inFilePtr);
line_number = 0;
while (readAndParse(inFilePtr, label, opcode, arg0, arg1, arg2)){
if (strcmp(opcode, "add") == 0){
o = 0;
sscanf(arg0, "%d", &a);
sscanf(arg1, "%d", &b);
sscanf(arg2, "%d", &c);
}
else if (strcmp(opcode, "nand") == 0){
o = 1;
sscanf(arg0, "%d", &a);
sscanf(arg1, "%d", &b);
sscanf(arg2, "%d", &c);
}
else if (strcmp(opcode, "lw") == 0){
o = 2;
sscanf(arg0, "%d", &a);
sscanf(arg1, "%d", &b);
if (!isNumber(arg2, &c)){
if (!find_label(&table, arg2, &c)){
printf("non-existant label: %s\n", arg2);
exit(1);
}
}
}
else if (strcmp(opcode, "sw") == 0){
o = 3;
sscanf(arg0, "%d", &a);
sscanf(arg1, "%d", &b);
if (!isNumber(arg2, &c)){
if (!find_label(&table, arg2, &c)){
printf("non-existant label: %s\n", arg2);
exit(1);
}
}
}
else if (strcmp(opcode, "beq") == 0){
o = 4;
sscanf(arg0, "%d", &a);
sscanf(arg1, "%d", &b);
if (!isNumber(arg2, &c)){
if (!find_label(&table, arg2, &c)){
printf("non-existant label: %s\n", arg2);
exit(1);
}
c = c - (line_number + 1);
}
}
else if (strcmp(opcode, "jalr") == 0){
o = 5;
sscanf(arg0, "%d", &a);
sscanf(arg1, "%d", &b);
c = 0;
}
else if (strcmp(opcode, "halt") == 0){
o = 6;
a = b = c = 0;
}
else if (strcmp(opcode, "noop") == 0){
o = 7;
a = b = c = 0;
}
else if (strcmp(opcode, ".fill") == 0){
o = -1;
if (!isNumber(arg0, &a)){
if (!find_label(&table, arg0, &a)){
printf("non-existant label: %s\n", arg0);
exit(1);
}
}
b = c = 0;
}
else{
printf("not real instruction found: %s\n", opcode);
exit(1);
}
if (encode_insanity(outFilePtr, o, a, b, c)){
printf("encoding error on line %d\n", line_number + 1);
exit(1);
}
++line_number;
}
free(table.word_space);
free(table.labels);
fclose(inFilePtr);
fclose(outFilePtr);
exit(0);
return(0);
}
/*
* Read and parse a line of the assembly-language file. Fields are returned
* in label, opcode, arg0, arg1, arg2 (these strings must have memory already
* allocated to them).
*
* Return values:
* 0 if reached end of file
* 1 if all went well
*
* exit(1) if line is too long.
*/
int
readAndParse(FILE *inFilePtr, char *label, char *opcode, char *arg0,
char *arg1, char *arg2)
{
char line[MAXLINELENGTH + 1];
char *ptr = line;
int l;
/* delete prior values */
label[0] = opcode[0] = arg0[0] = arg1[0] = arg2[0] = '\0';
/* read the line from the assembly-language file */
if (fgets(line, MAXLINELENGTH, inFilePtr) == NULL) {
/* reached end of file */
return(0);
}
if (feof(inFilePtr)){
l = strlen(line);
if (line[l-1] != '\n'){
line[l] = '\n';
line[l+1] = 0;
}
}
#if 0
char line[MAXLINELENGTH];
char *ptr = line;
/* delete prior values */
label[0] = opcode[0] = arg0[0] = arg1[0] = arg2[0] = '\0';
/* read the line from the assembly-language file */
if (fgets(line, MAXLINELENGTH, inFilePtr) == NULL) {
/* reached end of file */
return(0);
}
#endif
/* check for line too long (by looking for a \n) */
if (strchr(line, '\n') == NULL) {
/* line too long */
printf("error: line too long\n");
exit(1);
}
/* is there a label? */
ptr = line;
if (sscanf(ptr, "%[^\t\n\r ]", label)) {
/* successfully read label; advance pointer over the label */
ptr += strlen(label);
}
/*
* Parse the rest of the line. Would be nice to have real regular
* expressions, but scanf will suffice.
*/
sscanf(ptr, "%*[\t\n\r ]%[^\t\n\r ]%*[\t\n\r ]%[^\t\n\r ]%*[\t\n\r ]%[^\t\n\r ]%*[\t\n\r ]%[^\t\n\r ]",
opcode, arg0, arg1, arg2);
return(1);
}
int
isNumber(char *string, int *i)
{
return( (sscanf(string, "%d", i)) == 1);
}