#drinc:exec/miscellaneous.g #drinc:exec/memory.g #drinc:libraries/dos.g #drinc:util.g #toy.g #externs.g /* * system.d: contains routines for Amiga-specific system interface. */ uint FILE_NAME_LENGTH_MAX = 256, CODE_BUFFER_SIZE = 512, RUN_TIME_VAR_SIZE = 256 + 5 * 4; /* constants needed for AmigaDOS object file output */ ulong HUNK_CODE = 1001, HUNK_BSS = 1003, HUNK_RELOC32 = 1004, HUNK_END = 1010, HUNK_HEADER = 1011; type /* type for a linked lists of offsets within a hunk */ OffsetList_t = struct { *OffsetList_t ol_next; uint ol_offset; /* offset in hunk where reference is */ }, /* type for a list of external reference sets from one hunk to others */ Reference_t = struct { *Reference_t r_next; *OffsetList_t r_offsets;/* the list of references to this other */ uint r_offsetCount; /* how many references there are */ uint r_whichHunk; /* which hunk we are referencing */ }, /* type for all the information for an AmigaDOS code hunk */ HunkList_t = struct { *HunkList_t hl_next; *byte hl_code; /* the machine code of the hunk */ uint hl_codeLength; /* how long it is */ *Reference_t hl_references; /* its references to other hunks */ }; Handle_t StandardOutput, /* standard output handle for messages */ SourceInput, /* the input source file */ CodeOutput; /* the output object-code file */ uint ErrorCount; /* count of number of errors encountered */ [FILE_NAME_LENGTH_MAX] char InputFileName; *HunkList_t HunkList; /* list of hunks compiled so far */ *HunkList_t HunkCurrent; /* the one for the current proc */ **HunkList_t HunkTail; /* pointer to pointer to last hunk */ *HunkList_t MainCallHunk; /* the hunk which calls main */ uint MainCallOffset; /* offset in that hunk of the call */ uint HunkCount; /* count of hunks compiled so far */ uint CodeBufferPos; /* current position in code buffer */ [CODE_BUFFER_SIZE]byte CodeBuffer; bool MainDefined; /* we have seen a 'main' */ /* SOME ERROR PRINTING ROUTINES */ /* * printString - print a null-terminated string. */ proc printString(*char st)void: register *char p; p := st; while p* ~= '\e' do p := p + sizeof(char); od; ignore Write(StandardOutput, st, p - st); corp; /* * printInt - print an integer. */ proc printInt(register int n)void: [7] char buffer; register *char p; bool isNegative; if n < 0 then n := -n; isNegative := true; else isNegative := false; fi; buffer[6] := '\e'; p := &buffer[5]; while p* := n % 10 + '0'; n := n / 10; n ~= 0 do p := p - sizeof(char); od; if isNegative then p := p - sizeof(char); p* := '-'; fi; ignore Write(StandardOutput, p, &buffer[7] - p); corp; /* * errorPosition - print the position header for an error message. */ proc errorPosition(uint line, column)void: printString(&InputFileName[0]); printString("("); printInt(line); printString(","); printInt(column); printString(") - "); ErrorCount := ErrorCount + 1; corp; /* UTILITY SYSTEM INTERFACE ROUTINES */ /* * abort - something has gone wrong - print a message, close up, exit. */ proc abort(*char message)void: register *HunkList_t hl; register *Reference_t r; register *OffsetList_t ol; *HunkList_t hlTemp; *Reference_t rTemp; *OffsetList_t olTemp; printString(&InputFileName[0]); printString(": "); printString(message); printString(" - aborting\n"); hl := HunkList; while hl ~= nil do if hl*.hl_code ~= nil then memFree(hl*.hl_code, hl*.hl_codeLength); fi; r := hl*.hl_references; while r ~= nil do ol := r*.r_offsets; while ol ~= nil do olTemp := ol; ol := ol*.ol_next; memFree(olTemp, sizeof(OffsetList_t)); od; rTemp := r; r := r*.r_next; memFree(rTemp, sizeof(Reference_t)); od; hlTemp := hl; hl := hl*.hl_next; memFree(hlTemp, sizeof(HunkList_t)); od; lexTerm(); symbolTerm(); Close(CodeOutput); Close(SourceInput); Exit(RETURN_FAIL); corp; /* * memAlloc - allocate some memory. */ proc memAlloc(ulong length)arbptr: arbptr p; p := AllocMem(length, 0); if p = nil then abort("cannot allocate memory"); fi; p corp; /* * memFree - free some memory. */ proc memFree(arbptr p; ulong length)void: FreeMem(p, length); corp; /* SOURCE AND CODE INPUT/OUTPUT ROUTINES */ /* * readSource - read a bufferfull of data from the source file. */ proc readSource(*char buffer; ulong length)uint: Read(SourceInput, buffer, length * sizeof(char)) corp; /* * codeStartProc - setup for a new proc. */ proc codeStartProc(*SymbolEntry_t se)void: register *HunkList_t hl; if se ~= nil then se*.se_value := HunkCount; fi; hl := memAlloc(sizeof(HunkList_t)); hl*.hl_next := nil; hl*.hl_references := nil; hl*.hl_code := nil; HunkCurrent := hl; HunkTail* := hl; HunkTail := &hl*.hl_next; corp; /* * codeReference - the current proc is referencing another one or referencing * the global variables. */ proc codeReference(RelocCode_t rc; *SymbolEntry_t se; uint offset)void: register *HunkList_t hl; register *Reference_t r; register *OffsetList_t ol; register uint hunkNumber; if rc = rc_main then MainCallHunk := HunkCurrent; MainCallOffset := offset; else hunkNumber := if rc = rc_globalVariable then /* reference a global variable */ 1 elif rc = rc_none then /* reference a user proc */ se*.se_value else /* reference a run-time procedure */ rc - rc_printString + 2 /* 0 = startup, 1 = globals */ fi; hl := HunkCurrent; r := hl*.hl_references; while r ~= nil and r*.r_whichHunk ~= hunkNumber do r := r*.r_next; od; if r = nil then r := memAlloc(sizeof(Reference_t)); r*.r_next := hl*.hl_references; r*.r_whichHunk := hunkNumber; r*.r_offsets := nil; r*.r_offsetCount := 0; hl*.hl_references := r; fi; ol := memAlloc(sizeof(OffsetList_t)); ol*.ol_next := r*.r_offsets; ol*.ol_offset := offset; r*.r_offsets := ol; r*.r_offsetCount := r*.r_offsetCount + 1; fi; corp; /* * codeEndProc - finish processing the current proc. */ proc codeEndProc(*SymbolEntry_t se; *byte codePtr; uint codeLength)void: HunkCurrent*.hl_code := memAlloc(codeLength); BlockCopy(HunkCurrent*.hl_code, codePtr, codeLength); HunkCurrent*.hl_codeLength := codeLength; if se ~= nil and CharsEqual(se*.se_name, "main") then if MainCallHunk = nil then abort("conCheck - MainCallHunk = nil"); fi; HunkCurrent := MainCallHunk; codeReference(rc_none, se, MainCallOffset); MainDefined := true; fi; HunkCount := HunkCount + 1; corp; /* * codeWrite - write the given amount to the code file. */ proc codeWrite(arbptr buffer; uint length)void: if Write(CodeOutput, buffer, length) ~= length then abort("error on write to output file"); fi; corp; /* * codeFlush - flush the current contents of the code buffer. */ proc codeFlush()void: codeWrite(&CodeBuffer[0], CodeBufferPos); CodeBufferPos := 0; corp; /* * emitLong - emit a 4 byte value into the output code stream. */ proc emitLong(register ulong n)void: register *byte p; register uint i; if CodeBufferPos >= CODE_BUFFER_SIZE - 4 then codeFlush(); fi; p := &CodeBuffer[CodeBufferPos]; p* := n >> 24; p := p + 1; p* := n >> 16; p := p + 1; p* := n >> 8; p := p + 1; p* := n; CodeBufferPos := CodeBufferPos + 4; corp; /* TOP-LEVEL OF COMPILATION PROCESS */ /* * emitCode - emit the object code for the current input file. */ proc emitCode()void: register *HunkList_t hl; register *Reference_t r; register *OffsetList_t ol; *HunkList_t hlTemp; *Reference_t rTemp; *OffsetList_t olTemp; int globalSize; bool doneBss; if not MainDefined then errorHere("no 'main' defined"); fi; globalSize := getGlobalSize(); CodeBufferPos := 0; /* first, the header, which describes the hunks to follow */ emitLong(HUNK_HEADER); emitLong(0); emitLong(HunkCount); emitLong(0); emitLong(HunkCount - 1); doneBss := false; hl := HunkList; while hl ~= nil do emitLong((hl*.hl_codeLength + 3) / 4); if not doneBss then doneBss := true; emitLong((globalSize + 3) / 4); fi; hl := hl*.hl_next; od; /* and then the hunks for the proc's. Each has the proc's code in a code hunk, followed by that proc's references to the global variables, the run-time routines, and other proc's, in a reloc32 hunk. */ doneBss := false; hl := HunkList; while hl ~= nil do emitLong(HUNK_CODE); emitLong((hl*.hl_codeLength + 3) / 4); codeFlush(); codeWrite(hl*.hl_code, (hl*.hl_codeLength + 3) / 4 * 4); memFree(hl*.hl_code, hl*.hl_codeLength); r := hl*.hl_references; if r ~= nil then emitLong(HUNK_RELOC32); while r ~= nil do emitLong(r*.r_offsetCount); emitLong(r*.r_whichHunk); ol := r*.r_offsets; while ol ~= nil do emitLong(ol*.ol_offset); olTemp := ol; ol := ol*.ol_next; memFree(olTemp, sizeof(OffsetList_t)); od; rTemp := r; r := r*.r_next; memFree(rTemp, sizeof(Reference_t)); od; emitLong(0); fi; hlTemp := hl; hl := hl*.hl_next; memFree(hlTemp, sizeof(HunkList_t)); emitLong(HUNK_END); if not doneBss then doneBss := true; emitLong(HUNK_BSS); emitLong((globalSize + 3) / 4); emitLong(HUNK_END); fi; od; codeFlush(); corp; /* * objectSetup - initialization for object code output. */ proc objectSetup()void: MainDefined := false; MainCallHunk := nil; HunkList := nil; HunkTail := &HunkList; HunkCount := 1; outputRunTime(); setGlobalSize(RUN_TIME_VAR_SIZE); corp; /* * compileFile - all the motions to compile the current input file. */ proc compileFile()void: register TokenKind_t tk; objectSetup(); ErrorCount := 0; symbolInit(); lexInit(); declareVariables(sk_globalVariable); while tk := getSimpleToken(); tk ~= tk_eof do if tk = tk_proc then defineProc(); else errorHere("expecting proc definition"); while tk ~= tk_proc and tk ~= tk_eof do skipToken(); tk := getSimpleToken(); od; fi; od; lexTerm(); symbolTerm(); emitCode(); corp; /* * main - the whole thing starts here. */ proc main()void: extern _d_pars_initialize()void; register uint totalErrorCount; register *char parameter, p, q; bool doneOne; if OpenExecLibrary(0) ~= nil then if OpenDosLibrary(0) ~= nil then _d_pars_initialize(); StandardOutput := Output(); printString( "Toy compiler version 1.0, Copyright 1988 by Chris Gray\n"); doneOne := false; while parameter := GetPar(); parameter ~= nil do doneOne := true; p := parameter; while p* ~= '\e' do p := p + sizeof(char); od; q := p; while p ~= parameter and p* ~= '.' do p := p - sizeof(char); od; if p = parameter then p := q; fi; q := &InputFileName[0]; while parameter ~= p do q* := parameter*; q := q + sizeof(char); parameter := parameter + sizeof(char); od; q* := '.'; (q + sizeof(char))* := 't'; (q + 2 * sizeof(char))* := '\e'; SourceInput := Open(&InputFileName[0], MODE_OLDFILE); if SourceInput = 0 then printString(&InputFileName[0]); printString(": can't open input file\n"); else q* := '\e'; DeleteFile(&InputFileName[0]); CodeOutput := Open(&InputFileName[0], MODE_NEWFILE); if CodeOutput = 0 then printString(&InputFileName[0]); printString(": can't create output file\n"); else q* := '.'; printString(&InputFileName[0]); printString(":\n"); compileFile(); Close(CodeOutput); if ErrorCount ~= 0 then q* := '\e'; DeleteFile(&InputFileName[0]); printInt(ErrorCount); printString(" errors - output file '"); printString(&InputFileName[0]); printString("' deleted.\n"); totalErrorCount := totalErrorCount + ErrorCount; fi; fi; Close(SourceInput); fi; od; if not doneOne then printString("Use is: toyc file[.t]\n"); Exit(RETURN_WARN); else Exit( if totalErrorCount = 0 then RETURN_OK else RETURN_ERROR fi); fi; fi; CloseExecLibrary(); fi; corp;