diff --git a/src/cmd/smlrc/cgmips.c b/src/cmd/smlrc/cgmips.c index b69b3db..e22bdc3 100644 --- a/src/cmd/smlrc/cgmips.c +++ b/src/cmd/smlrc/cgmips.c @@ -21,10 +21,6 @@ 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. - -The views and conclusions contained in the software and documentation are those -of the authors and should not be interpreted as representing official policies, -either expressed or implied, of the FreeBSD Project. */ /*****************************************************************************/ @@ -519,6 +515,26 @@ void GenJumpIfNotZero(int label) MipsOpNumLabel, label); } +fpos_t GenPrologPos; + +STATIC +void GenWriteFrameSize(void) +{ + unsigned size = -CurFxnMinLocalOfs; + int pfx = size ? ' ' : '#'; + printf2("\t%csubu\t$29, $29, %10u\n", pfx, size); // 10 chars are enough for 32-bit unsigned ints +} + +STATIC +void GenUpdateFrameSize(void) +{ + fpos_t pos; + fgetpos(OutFile, &pos); + fsetpos(OutFile, &GenPrologPos); + GenWriteFrameSize(); + fsetpos(OutFile, &pos); +} + STATIC void GenFxnProlog(void) { @@ -549,6 +565,9 @@ void GenFxnProlog(void) MipsOpRegA0 + i, 0, MipsOpIndRegFp, 8 + 4 * i); } + + fgetpos(OutFile, &GenPrologPos); + GenWriteFrameSize(); } STATIC @@ -562,15 +581,11 @@ void GenGrowStack(int size) MipsOpConst, size); } -STATIC -void GenFxnProlog2(void) -{ - GenGrowStack(-CurFxnMinLocalOfs); -} - STATIC void GenFxnEpilog(void) { + GenUpdateFrameSize(); + GenPrintInstr2Operands(MipsInstrMov, 0, MipsOpRegSp, 0, MipsOpRegFp, 0); @@ -2225,3 +2240,4 @@ void GenFin(void) } #endif } + diff --git a/src/cmd/smlrc/cgx86.c b/src/cmd/smlrc/cgx86.c index 300333f..7c519a5 100644 --- a/src/cmd/smlrc/cgx86.c +++ b/src/cmd/smlrc/cgx86.c @@ -21,10 +21,6 @@ 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. - -The views and conclusions contained in the software and documentation are those -of the authors and should not be interpreted as representing official policies, -either expressed or implied, of the FreeBSD Project. */ /*****************************************************************************/ @@ -791,6 +787,50 @@ void GenJumpIfNotZero(int label) X86OpNumLabel, label); } +fpos_t GenPrologPos; + +STATIC +void GenWriteFrameSize(void) +{ + unsigned size = -CurFxnMinLocalOfs; + int pfx = size ? ' ' : ';'; +#ifdef CAN_COMPILE_32BIT + if (SizeOfWord == 4 && + OutputFormat != FormatSegHuge && + WindowsStack) + { + int pfx = (size >= 4096) ? ' ' : ';'; + // When targeting Windows, call equivalent of _chkstk() to + // correctly grow the stack page by page by probing it + if (!WinChkStkLabel) + WinChkStkLabel = -LabelCnt++; // reserve a label for _chkstk() and mark unused + if (WinChkStkLabel < 0 && pfx == ' ') + WinChkStkLabel = -WinChkStkLabel; // _chkstk() has been used at least once + + printf2("\t%cmov\teax, %10u\n", pfx, size); // 10 chars are enough for 32-bit unsigned ints + printf2("\t%ccall\t", pfx); + GenPrintNumLabel((WinChkStkLabel < 0) ? -WinChkStkLabel : WinChkStkLabel); + puts2(""); + } +#endif + if (SizeOfWord == 2) + printf2("\t%csub\tsp, %10u\n", pfx, size); // 10 chars are enough for 32-bit unsigned ints +#ifdef CAN_COMPILE_32BIT + else + printf2("\t%csub\tesp, %10u\n", pfx, size); // 10 chars are enough for 32-bit unsigned ints +#endif +} + +STATIC +void GenUpdateFrameSize(void) +{ + fpos_t pos; + fgetpos(OutFile, &pos); + fsetpos(OutFile, &GenPrologPos); + GenWriteFrameSize(); + fsetpos(OutFile, &pos); +} + STATIC void GenFxnProlog(void) { @@ -799,6 +839,8 @@ void GenFxnProlog(void) GenPrintInstr2Operands(X86InstrMov, 0, X86OpRegBpWord, 0, X86OpRegSpWord, 0); + fgetpos(OutFile, &GenPrologPos); + GenWriteFrameSize(); } STATIC @@ -806,39 +848,15 @@ void GenGrowStack(int size) { if (!size) return; -#ifdef CAN_COMPILE_32BIT - if (SizeOfWord == 4 && - OutputFormat != FormatSegHuge && - WindowsStack && - size >= 4096) - { - // When targeting Windows, call equivalent of _chkstk() to - // correctly grow the stack page by page by probing it - if (!WinChkStkLabel) - WinChkStkLabel = LabelCnt++; - - GenPrintInstr2Operands(X86InstrMov, 0, - X86OpRegAWord, 0, - X86OpConst, size); - printf2("\tcall\t"); - GenPrintNumLabel(WinChkStkLabel); // TBD??? use dedicated instr/op fxn??? - puts2(""); - } -#endif GenPrintInstr2Operands(X86InstrSub, 0, X86OpRegSpWord, 0, X86OpConst, size); } -STATIC -void GenFxnProlog2(void) -{ - GenGrowStack(-CurFxnMinLocalOfs); -} - STATIC void GenFxnEpilog(void) { + GenUpdateFrameSize(); GenPrintInstrNoOperand(X86InstrLeave); GenPrintInstrNoOperand(X86InstrRet); } @@ -899,10 +917,13 @@ void GenIsrProlog(void) puts2("\tpush\tebp\n" "\tmov\tebp, esp"); + fgetpos(OutFile, &GenPrologPos); + GenWriteFrameSize(); } void GenIsrEpilog(void) { + GenUpdateFrameSize(); puts2("\tdb\t0x66\n\tleave"); puts2("\tpop\teax"); // fake return address @@ -3171,6 +3192,7 @@ void GenFin(void) puts2(CodeHeaderFooter[0]); GenNumLabel(StructCpyLabel); + CurFxnMinLocalOfs = 0; GenFxnProlog(); if (SizeOfWord == 2) @@ -3248,6 +3270,7 @@ void GenFin(void) puts2(CodeHeaderFooter[0]); GenNumLabel(StructPushLabel); + CurFxnMinLocalOfs = 0; GenFxnProlog(); if (SizeOfWord == 2) @@ -3336,7 +3359,7 @@ void GenFin(void) #endif #ifdef CAN_COMPILE_32BIT - if (WinChkStkLabel) + if (WinChkStkLabel > 0) // if _chkstk() has been used at least once { // When targeting Windows, simulate _chkstk() to // correctly grow the stack page by page by probing it @@ -3378,3 +3401,4 @@ void GenFin(void) } } } + diff --git a/src/cmd/smlrc/lb.c b/src/cmd/smlrc/lb.c index 0e472fa..e8dd16a 100644 --- a/src/cmd/smlrc/lb.c +++ b/src/cmd/smlrc/lb.c @@ -1,5 +1,5 @@ /* -Copyright (c) 2013-2014, Alexey Frunze +Copyright (c) 2013-2015, Alexey Frunze All rights reserved. Redistribution and use in source and binary forms, with or without @@ -21,10 +21,6 @@ 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. - -The views and conclusions contained in the software and documentation are those -of the authors and should not be interpreted as representing official policies, -either expressed or implied, of the FreeBSD Project. */ #ifndef __APPLE__ @@ -749,6 +745,22 @@ int WriteFile(unsigned Handle, "push dword [ebp+8]\n" "call [__imp__WriteFile]"); } + +extern unsigned (*_imp__SetFilePointer)(unsigned Handle, + int lDistanceToMove, + int* lpDistanceToMoveHigh, + unsigned dwMoveMethod); +unsigned SetFilePointer(unsigned Handle, + int lDistanceToMove, + int* lpDistanceToMoveHigh, + unsigned dwMoveMethod) +{ + asm("push dword [ebp+20]\n" + "push dword [ebp+16]\n" + "push dword [ebp+12]\n" + "push dword [ebp+8]\n" + "call [__imp__SetFilePointer]"); +} #endif // _WIN32 #ifdef _RETROBSD @@ -786,7 +798,7 @@ int OsCreateOrTruncate(char* name) #ifdef _LINUX asm("mov eax, 5\n" // sys_open "mov ebx, [ebp + 8]\n" - "mov ecx, 0x641\n" // truncate if exists, else create, writing only + "mov ecx, 0x241\n" // truncate if exists, else create, writing only "mov edx, 664o\n" // rw-rw-r-- "int 0x80\n" "mov ebx, eax\n" @@ -1055,6 +1067,67 @@ int OsWrite(int fd, void* p, unsigned s) #endif } +#ifndef __SMALLER_C_16__ +long OsLseek(int fd, long ofs, int whence) +{ +#ifdef _RETROBSD + long pos; + asm volatile ("move $4, %1\n" + "move $5, %2\n" + "move $6, %3\n" + "syscall 19\n" // SYS_lseek + "nop\n" + "nop\n" + "move %0, $2\n" + : "=r" (pos) + : "r" (fd), "r" (ofs), "r" (whence) + : "$2", "$4", "$5", "$6"); + return pos; +#else +#ifdef _LINUX + asm("mov eax, 19\n" // sys_lseek + "mov ebx, [ebp + 8]\n" + "mov ecx, [ebp + 12]\n" + "mov edx, [ebp + 16]\n" + "int 0x80"); +#else +#ifdef _WIN32 + return SetFilePointer(fd, ofs, 0, whence); +#else + asm("mov ah, 0x42\n" + "mov bx, [bp + 8]\n" + "mov dx, [bp + 12]\n" + "mov cx, [bp + 12 + 2]\n" + "mov al, [bp + 16]\n" + "int 0x21"); + asm("sbb ebx, ebx\n" + "and eax, 0xffff\n" + "shl edx, 16\n" + "or eax, edx\n" + "or eax, ebx"); +#endif +#endif +#endif +} +#else +int OsLseek16(int fd, unsigned short ofs[2], int whence) +{ + asm("mov ah, 0x42\n" + "mov bx, [bp + 4]\n" + "mov si, [bp + 6]"); + asm("mov dx, [si]\n" + "mov cx, [si + 2]\n" + "mov al, [bp + 8]\n" + "int 0x21"); + asm("sbb bx, bx\n" + "or ax, bx\n" + "or dx, bx\n" + "mov [si], ax\n" + "mov [si + 2], dx\n" + "mov ax, bx"); +} +#endif + #ifdef _DOS unsigned DosGetPspSeg(void) { @@ -1398,4 +1471,81 @@ int fclose(FILE* stream) --__FileCnt__; return OsClose(fd); } + +struct fpos_t_ +{ + union + { + unsigned short halves[2]; // for 16-bit memory models without 32-bit longs + int align; // for alignment on machine word boundary + } u; +}; // keep in sync with stdio.h !!! +#define fpos_t struct fpos_t_ + +// Note, these fgetpos() and fsetpos() are implemented for write-only files + +int fgetpos(FILE* stream, fpos_t* pos) +{ + unsigned i = (unsigned)stream, fd; + + fd = __FileHandles__[--i]; + +#ifndef __SMALLER_C_16__ +{ + long p; + if ((p = OsLseek(fd, 0, 1/*SEEK_CUR*/)) < 0) + return -1; + + p += __FileBufPos__[i]; + pos->u.align = p; +} +#else +{ + unsigned short p[2]; + p[0] = p[1] = 0; + if (OsLseek16(fd, p, 1/*SEEK_CUR*/) < 0) + return -1; + p[1] += __FileBufPos__[i] > 0xFFFF - p[0]; + p[0] += __FileBufPos__[i]; + pos->u.halves[0] = p[0]; + pos->u.halves[1] = p[1]; +} +#endif + return 0; +} + +int fsetpos(FILE* stream, fpos_t* pos) +{ + unsigned i = (unsigned)stream, fd; + unsigned sz; + + fd = __FileHandles__[--i]; + + // flush + sz = __FileBufPos__[i]; + if (sz) + { + if ((unsigned)OsWrite(fd, __FileBufs__[i], sz) != sz) + return -1; + } + + // seek +#ifndef __SMALLER_C_16__ +{ + long p = pos->u.align; + if ((p = OsLseek(fd, p, 0/*SEEK_SET*/)) < 0) + return -1; +} +#else +{ + if (OsLseek16(fd, pos->u.halves, 0/*SEEK_SET*/) < 0) + return -1; +} +#endif + + __FileBufDirty__[i] = 0; + __FileBufSize__[i] = __FileBufPos__[i] = 0; + + return 0; +} #endif /*__APPLE__*/ diff --git a/src/cmd/smlrc/license.txt b/src/cmd/smlrc/license.txt index 18e7bf9..b08bdea 100644 --- a/src/cmd/smlrc/license.txt +++ b/src/cmd/smlrc/license.txt @@ -1,14 +1,14 @@ -Copyright (c) 2012, Alexey Frunze +Copyright (c) 2012-2015, Alexey Frunze All rights reserved. Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: +modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. + list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. + and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -21,6 +21,3 @@ 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. -The views and conclusions contained in the software and documentation are those -of the authors and should not be interpreted as representing official policies, -either expressed or implied, of the FreeBSD Project. diff --git a/src/cmd/smlrc/readme.txt b/src/cmd/smlrc/readme.txt index e349681..5294ccf 100644 --- a/src/cmd/smlrc/readme.txt +++ b/src/cmd/smlrc/readme.txt @@ -7,14 +7,39 @@ that can then be assembled and linked into DOS, Windows and Linux programs. Code generation for MIPS CPUs is also supported (primarily for RetroBSD). -The compiler is capable of compiling its own source code. +Code generation for the TR3200 CPU and VASM is supported (see Trillek). -You can fully recompile the compiler only with itself and NASM for the -x86 platform (no linker is necessary). +The compiler is capable of compiling itself. + +The core compiler comes with a linker and a compiler driver (the driver +invokes the core compiler, the assembler, and the linker and supports +options similar to those of gcc). + +There's no decent preprocessor in Smaller C as of now, but the compiler +driver can invoke gcc (or gcc.exe) for preprocessing if instructed. + +The standard C library is work-in-progress and it's close to completion. See the Wiki for more up-to-date details: http://github.com/alexfru/SmallerC/wiki +For the lack of a better place, you can discuss Smaller C here: +https://hackaday.io/project/5569-smaller-c + Links: NASM: http://nasm.us/ +YASM: http://yasm.tortall.net/ +CWSDPMI: http://homer.rice.edu/~sandmann/cwsdpmi/ +HX DOS Extender: https://web.archive.org/web/20141003032346/http://www.japheth.de/ RetroBSD: http://retrobsd.org/ +VASM: http://sun.hasenbraten.de/vasm/ +Trillek: http://trillek.org/ + +Normative and other useful documents on C: +C99 + TC1 + TC2 + TC3, WG14 N1256: + http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf +Rationale for C99: + http://www.open-std.org/jtc1/sc22/wg14/www/docs/C99RationaleV5.10.pdf +The New C Standard: An Economic and Cultural Commentary: + http://www.knosof.co.uk/cbook/cbook.html + diff --git a/src/cmd/smlrc/smlrc.c b/src/cmd/smlrc/smlrc.c index 81fd70f..6687d9e 100644 --- a/src/cmd/smlrc/smlrc.c +++ b/src/cmd/smlrc/smlrc.c @@ -21,10 +21,6 @@ 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. - -The views and conclusions contained in the software and documentation are those -of the authors and should not be interpreted as representing official policies, -either expressed or implied, of the FreeBSD Project. */ /*****************************************************************************/ @@ -159,6 +155,17 @@ int fprintf(FILE*, char*, ...); int vprintf(char*, void*); //int vfprintf(FILE*, char*, va_list); int vfprintf(FILE*, char*, void*); +struct fpos_t_ +{ + union + { + unsigned short halves[2]; // for 16-bit memory models without 32-bit longs + int align; // for alignment on machine word boundary + } u; +}; // keep in sync with stdio.h !!! +#define fpos_t struct fpos_t_ +int fgetpos(FILE*, fpos_t*); +int fsetpos(FILE*, fpos_t*); #endif // #ifndef __SMALLER_C__ @@ -406,8 +413,6 @@ void GenJumpIfEqual(int val, int Label); STATIC void GenFxnProlog(void); STATIC -void GenFxnProlog2(void); -STATIC void GenFxnEpilog(void); void GenIsrProlog(void); void GenIsrEpilog(void); @@ -4726,31 +4731,24 @@ void DetermineVaListType(void) #endif // DETERMINE_VA_LIST #endif // __SMALLER_C__ -// Equivalent to puts() but outputs to OutFile -// if it's not NULL. +// Equivalent to puts() but outputs to OutFile. STATIC int puts2(char* s) { int res; - if (OutFile) + if (!OutFile) + return 0; + // Turbo C++ 1.01's fputs() returns EOF if s is empty, which is wrong. + // Hence the workaround. + if (*s == '\0' || (res = fputs(s, OutFile)) >= 0) { - // Turbo C++ 1.01's fputs() returns EOF if s is empty, which is wrong. - // Hence the workaround. - if (*s == '\0' || (res = fputs(s, OutFile)) >= 0) - { - // unlike puts(), fputs() doesn't append '\n', append it manually - res = fputc('\n', OutFile); - } - } - else - { - res = puts(s); + // unlike puts(), fputs() doesn't append '\n', append it manually + res = fputc('\n', OutFile); } return res; } -// Equivalent to printf() but outputs to OutFile -// if it's not NULL. +// Equivalent to printf() but outputs to OutFile. STATIC int printf2(char* format, ...) { @@ -4763,31 +4761,24 @@ int printf2(char* format, ...) void* vl = &format + 1; #endif + if (!OutFile) + return 0; #ifndef __SMALLER_C__ - if (OutFile) - res = vfprintf(OutFile, format, vl); - else - res = vprintf(format, vl); + res = vfprintf(OutFile, format, vl); #else // TBD!!! This is not good. Really need the va_something macros. #ifdef DETERMINE_VA_LIST if (VaListType == 2) { // va_list is a one-element array containing a pointer - if (OutFile) - res = vfprintf(OutFile, format, &vl); - else - res = vprintf(format, &vl); + res = vfprintf(OutFile, format, &vl); } else // if (VaListType == 1) // fallthrough #endif // DETERMINE_VA_LIST { // va_list is a pointer - if (OutFile) - res = vfprintf(OutFile, format, vl); - else - res = vprintf(format, vl); + res = vfprintf(OutFile, format, vl); } #endif // __SMALLER_C__ @@ -4881,7 +4872,7 @@ void warning(char* format, ...) warnCnt++; - if (!(warnings && OutFile)) + if (!warnings) return; printf("Warning in \"%s\" (%d:%d)\n", FileNames[fidx], LineNo, LinePos); @@ -6928,7 +6919,6 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label) // local variables to the symbol table and parse the body. int undoSymbolsPtr = SyntaxStackCnt; int undoIdents = IdentTableLen; - int locAllocLabel = (LabelCnt += 2) - 2; int i; int Main; @@ -6941,7 +6931,7 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label) gotoLabCnt = 0; - if (verbose && OutFile) + if (verbose) printf("%s()\n", CurFxnName); ParseLevel++; @@ -6959,7 +6949,6 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label) puts2(CurHeaderFooter[0]); GenLabel(CurFxnName, Static); - CurFxnEpilogLabel = LabelCnt++; #ifndef MIPS #ifdef CAN_COMPILE_32BIT @@ -6969,9 +6958,7 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label) #endif #endif GenFxnProlog(); - - GenJumpUncond(locAllocLabel + 1); - GenNumLabel(locAllocLabel); + CurFxnEpilogLabel = LabelCnt++; AddFxnParamSymbols(lastSyntaxPtr); @@ -7013,10 +7000,6 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label) #endif GenFxnEpilog(); - GenNumLabel(locAllocLabel + 1); - GenFxnProlog2(); - GenJumpUncond(locAllocLabel); - puts2(CurHeaderFooter[1]); CurHeaderFooter = NULL; @@ -8223,6 +8206,8 @@ int main(int argc, char** argv) if (!FileCnt) error("Input file not specified\n"); + if (!OutFile) + error("Output file not specified\n"); GenInitFinalize(); @@ -8272,7 +8257,7 @@ int main(int argc, char** argv) GenStartCommentLine(); printf2("Next label number: %d\n", LabelCnt); - if (warnings && warnCnt && OutFile) + if (warnings && warnCnt) printf("%d warnings\n", warnCnt); GenStartCommentLine(); printf2("Compilation succeeded.\n"); @@ -8281,3 +8266,4 @@ int main(int argc, char** argv) return 0; } +