Merge pull request #60 from alexfru/master

Update Smaller C.
This commit is contained in:
Serge Vakulenko
2015-08-20 23:19:59 -07:00
6 changed files with 300 additions and 102 deletions

View File

@@ -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
}

View File

@@ -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)
}
}
}

View File

@@ -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__*/

View File

@@ -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.

View File

@@ -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

View File

@@ -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;
}