/************************************************************************ * File: assemble.c * * Author: Karl Abrahamson * * Written: February 2002 * * Description: * * Convert a byte code program from symbolic form to binary form. * * Tab stops: Every 8 characters * ************************************************************************/ /************************************************************************* * Copyright 2002 Karl Abrahamson. All rights reserved. * * * * This software is provided by the author "as is" and any * * express or implied warranties, including, but not limited to, the * * implied warranties of merchantability and fitness for a particular * * purpose are disclaimed. In no event shall the author be liable * * for any direct, indirect, incidental, special, exemplary, or * * consequential damages (including, but not limited to, procurement * * of substitute goods or services; loss of use, data, or profits; or * * business interruption) however caused and on any theory of liability, * * whether in contract, strict liability, or tort (including negligence * * or otherwise) arising in any way out of the use of this software, * * even if advised of the possibility of such damage. * *************************************************************************/ /************************************************************************ * SYMBOLIC_FORMS OF INSTRUCTIONS * ************************************************************************ * In the following, k is an integer constant and str is a string. * * * * Comments * * -------- * * From ; to end of line. * * * * Sections: * * --------- * * * * MS_INTEGER_CONSTANT str * * * * MS_REAL_CONSTANT str * * * * MS_FUNCTION str * * ... (executable instruction: see below) * * MS_END * * * * MS_INTEGER_GLOBAL * * * * MS_REAL_GLOBAL * * * * MS_INTEGER_ARRAY_GLOBAL k * * * * MS_REAL_ARRAY_GLOBAL k * * * * MS_START str * * * * Executable instructions: * * ----------------------- * * * * One byte instructions * * * * M_POP_INTEGER * * M_POP_REAL * * M_POP_ARRAY * * M_INTEGER_ADD * * M_INTEGER_SUBTRACT * * M_INTEGER_MULTIPLY * * M_INTEGER_DIVIDE * * M_INTEGER_MOD * * M_REAL_ADD * * M_REAL_SUBTRACT * * M_REAL_MULTIPLY * * M_REAL_DIVIDE * * M_COMPARE_INTEGERS * * M_COMPARE_REALS * * M_MAKE_INTEGER_ARRAY * * M_MAKE_REAL_ARRAY * * M_DELETE_ARRAY * * M_INDEX * * M_STORE_INTEGER_INDEXED * * M_STORE_REAL_INDEXED * * M_RETURN_INTEGER * * M_RETURN_REAL * * M_RETURN * * M_READ_INTEGER * * M_READ_REAL * * M_READ_CHAR * * M_WRITE_INTEGER * * M_WRITE_REAL * * M_WRITE_CHAR * * * * Two byte instructions * * Each is followed by the number of the parameter. * * * * M_PUSH_INTEGER k * * M_PUSH_INTEGER_CONSTANT k * * M_PUSH_REAL_CONSTANT k * * M_ALLOC k * * M_DEALLOC k * * M_FETCH_LOCAL_INTEGER k * * M_FETCH_LOCAL_REAL k * * M_FETCH_LOCAL_ARRAY k * * M_STORE_LOCAL_INTEGER k * * M_STORE_LOCAL_REAL k * * M_STORE_LOCAL_ARRAY k * * M_FETCH_PARAM_INTEGER k * * M_FETCH_PARAM_REAL k * * M_FETCH_PARAM_ARRAY k * * M_STORE_PARAM_INTEGER k * * M_STORE_PARAM_REAL k * * M_STORE_PARAM_ARRAY k * * M_FETCH_GLOBAL_INTEGER k * * M_FETCH_GLOBAL_REAL k * * M_FETCH_GLOBAL_ARRAY k * * M_STORE_GLOBAL_INTEGER k * * M_STORE_GLOBAL_REAL k * * M_STORE_GLOBAL_ARRAY k * * M_LABEL k * * M_GOTO k * * M_GOTO_IF_ZERO k * * M_GOTO_IF_NOT_ZERO k * * M_GOTO_IF_POSITIVE k * * M_GOTO_IF_NOT_POSITIVE k * * M_GOTO_IF_NEGATIVE k * * M_GOTO_IF_NOT_NEGATIVE k * * M_GOTO_IF_FAILED k * * M_GOTO_IF_EOF k * * * * Call instruction * * M_CALL k str * ************************************************************************/ #include #include #include #include "machinedefs.h" #define USE_SIZED_INSTRUCTION_NAME #include "instinfo.c" #define MAX_INSTR_NAME_LENGTH 64 #define MAX_NAME_LENGTH 64 /************************************************************************ * LINE * ************************************************************************ * Variable line holds the current line number. * ************************************************************************/ int line = 1; /************************************************************************ * SKIPWHITE * ************************************************************************ * Skip over leading white space and comments (;...) in file INF. * ************************************************************************/ void skipwhite(FILE *inf) { int c = getc(inf); while(c != EOF && (isspace(c) || c == ';')) { if(c == ';') { while(c != EOF && c != '\n') c = getc(inf); } if(c == '\n') line++; c = getc(inf); } if(c != EOF) ungetc(c, inf); } /************************************************************************ * READSTRING * ************************************************************************ * Read a string from file INF, up to white space, and store the * * string in buffer buf. Skip over leading white space and comments * * first. * * * * Return 1 on success, -1 on end of file. * ************************************************************************/ int readstring(FILE *inf, char *buf) { int k, c; skipwhite(inf); c = getc(inf); k = 0; while(c != EOF && !isspace(c) && c != ';') { buf[k++] = c; c = getc(inf); } buf[k] = '\0'; if(c != EOF) ungetc(c, inf); return (k > 0) ? 1 : -1; } /************************************************************************ * COPY_STRING * ************************************************************************ * Copy a (white-space or comment deliminated) string from INF to * * OUTF. LINENO is the line number to report if there is an error. * ************************************************************************/ void copy_string(FILE *inf, FILE *outf, int lineno) { char name[MAX_NAME_LENGTH + 1]; skipwhite(inf); if(readstring(inf, name) > 0) { fprintf(outf, "%s%c", name, 0); } else { fprintf(stderr, "Line %d: name missing\n", lineno); } } /************************************************************************ * COPY_NUMBER * ************************************************************************ * Copy an integer from INF to OUTF. LINENO is the line number to * * report if there is an error. * ************************************************************************/ void copy_number(FILE *inf, FILE *outf, int lineno) { int n; skipwhite(inf); if(fscanf(inf, "%d", &n) > 0) { if(n >= 0 && n < 256) putc(n, outf); else fprintf(stderr, "Line %d: number out of range\n", lineno); } else { fprintf(stderr, "Line %d: integer parameter missing\n", lineno); } } /************************************************************************ * ASSEMBLE_FUNCTION_BODY * ************************************************************************ * Read the body of a function from INF and copy its code to OUTF. * ************************************************************************/ void assemble_function_body(FILE *inf, FILE* outf) { char buffer[MAX_INSTR_NAME_LENGTH + 1]; int k, ok; buffer[0] = 0; skipwhite(inf); ok = readstring(inf, buffer); while(ok > 0 && strcmp(buffer, "MS_END") != 0) { /*----------------------------------* * Look for a one byte instruction. * *----------------------------------*/ for(k = 0; one_byte_instruction_name[k] != NULL; k++) { if(strcmp(buffer, one_byte_instruction_name[k]) == 0) { putc(M_POP_INTEGER + k, outf); goto next_instruction; } } /*----------------------------------* * Look for a two byte instruction. * *----------------------------------*/ for(k = 0; two_byte_instruction_name[k] != NULL; k++) { if(strcmp(buffer, two_byte_instruction_name[k]) == 0) { putc(M_PUSH_INTEGER + k, outf); copy_number(inf, outf, line); goto next_instruction; } } /*---------------------------------* * Try to read a call instruction. * *---------------------------------*/ if(strcmp(buffer, "M_CALL") == 0) { int lineno = line; putc(M_CALL, outf); copy_number(inf, outf, lineno); copy_string(inf, outf, lineno); goto next_instruction; } /*----------------------* * Unknown instruction. * *----------------------*/ fprintf(stderr, "Unknown instruction %s\n", buffer); next_instruction: skipwhite(inf); ok = readstring(inf, buffer); } if(ok <= 0) { fprintf(stderr, "Line %d: missing MS_END\n", line); } putc(MS_END, outf); } /************************************************************************ * ASSEMBLE_SECTIONS * ************************************************************************ * Read a sequence of sections from INF and write their code to OUTF. * ************************************************************************/ void assemble_sections(FILE *inf, FILE *outf) { char buffer[MAX_INSTR_NAME_LENGTH + 1]; int ok; buffer[0] = 0; skipwhite(inf); ok = readstring(inf, buffer); while(ok > 0) { if(strcmp(buffer, "MS_INTEGER_CONSTANT") == 0) { putc(MS_INTEGER_CONSTANT, outf); copy_string(inf, outf, line); } else if(strcmp(buffer, "MS_REAL_CONSTANT") == 0) { putc(MS_REAL_CONSTANT, outf); copy_string(inf, outf, line); } else if(strcmp(buffer, "MS_INTEGER_CONSTANT") == 0) { putc(MS_INTEGER_CONSTANT, outf); copy_string(inf, outf, line); } else if(strcmp(buffer, "MS_FUNCTION") == 0) { putc(MS_FUNCTION, outf); copy_string(inf, outf, line); assemble_function_body(inf, outf); } else if(strcmp(buffer, "MS_INTEGER_GLOBAL") == 0) { putc(MS_INTEGER_GLOBAL, outf); } else if(strcmp(buffer, "MS_REAL_GLOBAL") == 0) { putc(MS_REAL_GLOBAL, outf); } else if(strcmp(buffer, "MS_INTEGER_ARRAY_GLOBAL") == 0) { putc(MS_INTEGER_ARRAY_GLOBAL, outf); copy_number(inf, outf, line); } else if(strcmp(buffer, "MS_REAL_ARRAY_GLOBAL") == 0) { putc(MS_REAL_ARRAY_GLOBAL, outf); copy_number(inf, outf, line); } else if(strcmp(buffer, "MS_START") == 0) { putc(MS_START, outf); copy_string(inf, outf, line); } else { fprintf(stderr, "Unknown section command %s\n", buffer); } skipwhite(inf); ok = readstring(inf, buffer); } } /************************************************************************ * MAIN * ************************************************************************/ int main(int argc, char **argv) { FILE *inf, *outf; if(argc != 3) { fprintf(stderr, "usage: assemble file.i file.m\n"); return 1; } inf = fopen(argv[1], "r"); if(inf == NULL) { fprintf(stderr, "Cannot open file %s for reading\n", argv[1]); return 1; } outf = fopen(argv[2], "wb"); if(outf == NULL) { fprintf(stderr, "Cannot open file %s for writing\n", argv[2]); fclose(inf); return 1; } assemble_sections(inf,outf); fclose(inf); fclose(outf); return 0; }