Bugfixes
- properly sign-/zero-extend returned values, e.g. the following
function must return 255 and not -1:
unsigned char f(void) { return -1; }
- properly decay arrays on the left side of ->, e.g. the following must
compile:
{
struct {char c;} s[1];
s[0].c = 'a'; putchar(s[0].c);
(s+0)->c = 'b'; putchar(s[0].c);
(*s).c = 'c'; putchar(s[0].c);
s->c = 'd'; putchar(s[0].c);
putchar('\n');
}
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2012-2014, Alexey Frunze
|
||||
Copyright (c) 2012-2015, Alexey Frunze
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -637,14 +637,22 @@ void GenFxnProlog(void)
|
||||
}
|
||||
|
||||
STATIC
|
||||
void GenLocalAlloc(int size)
|
||||
void GenGrowStack(int size)
|
||||
{
|
||||
if (!size)
|
||||
return;
|
||||
GenPrintInstr3Operands(MipsInstrSubU, 0,
|
||||
MipsOpRegSp, 0,
|
||||
MipsOpRegSp, 0,
|
||||
MipsOpConst, size);
|
||||
}
|
||||
|
||||
STATIC
|
||||
void GenFxnProlog2(void)
|
||||
{
|
||||
GenGrowStack(-CurFxnMinLocalOfs);
|
||||
}
|
||||
|
||||
STATIC
|
||||
void GenFxnEpilog(void)
|
||||
{
|
||||
@@ -669,6 +677,12 @@ void GenFxnEpilog(void)
|
||||
MipsOpRegRa, 0);
|
||||
}
|
||||
|
||||
STATIC
|
||||
int GenMaxLocalsSize(void)
|
||||
{
|
||||
return 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
STATIC
|
||||
int GenGetBinaryOperatorInstr(int tok)
|
||||
{
|
||||
@@ -1706,7 +1720,7 @@ void GenExpr0(void)
|
||||
GenPushReg();
|
||||
gotUnary = 0;
|
||||
if (maxCallDepth != 1 && v < 16)
|
||||
GenLocalAlloc(16 - v);
|
||||
GenGrowStack(16 - v);
|
||||
paramOfs = v - 4;
|
||||
if (maxCallDepth == 1 && paramOfs >= 0 && paramOfs <= 12)
|
||||
{
|
||||
@@ -1760,7 +1774,7 @@ void GenExpr0(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
GenLocalAlloc(16);
|
||||
GenGrowStack(16);
|
||||
}
|
||||
if (stack[i - 1][0] == tokIdent)
|
||||
{
|
||||
@@ -1774,7 +1788,7 @@ void GenExpr0(void)
|
||||
}
|
||||
if (v < 16)
|
||||
v = 16;
|
||||
GenLocalAlloc(-v);
|
||||
GenGrowStack(-v);
|
||||
break;
|
||||
|
||||
case tokUnaryStar:
|
||||
@@ -2399,4 +2413,3 @@ void GenFin(void)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2012-2014, Alexey Frunze
|
||||
Copyright (c) 2012-2015, Alexey Frunze
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -827,8 +827,10 @@ void GenFxnProlog(void)
|
||||
}
|
||||
|
||||
STATIC
|
||||
void GenLocalAlloc(int size)
|
||||
void GenGrowStack(int size)
|
||||
{
|
||||
if (!size)
|
||||
return;
|
||||
#ifdef CAN_COMPILE_32BIT
|
||||
if (SizeOfWord == 4 &&
|
||||
OutputFormat != FormatSegHuge &&
|
||||
@@ -860,6 +862,12 @@ void GenLocalAlloc(int size)
|
||||
X86OpConst, size);
|
||||
}
|
||||
|
||||
STATIC
|
||||
void GenFxnProlog2(void)
|
||||
{
|
||||
GenGrowStack(-CurFxnMinLocalOfs);
|
||||
}
|
||||
|
||||
STATIC
|
||||
void GenFxnEpilog(void)
|
||||
{
|
||||
@@ -867,6 +875,16 @@ void GenFxnEpilog(void)
|
||||
GenPrintInstrNoOperand(X86InstrRet);
|
||||
}
|
||||
|
||||
STATIC
|
||||
int GenMaxLocalsSize(void)
|
||||
{
|
||||
#ifdef CAN_COMPILE_32BIT
|
||||
if (SizeOfWord == 4 && OutputFormat != FormatSegHuge)
|
||||
return 0x7FFFFFFF;
|
||||
#endif
|
||||
return 0x7FFF;
|
||||
}
|
||||
|
||||
#ifdef CAN_COMPILE_32BIT
|
||||
/*
|
||||
struct INTREGS
|
||||
@@ -2654,8 +2672,7 @@ void GenExpr1(void)
|
||||
GenPrintInstr1Operand(X86InstrCall, 0,
|
||||
X86OpRegAWord, 0);
|
||||
}
|
||||
if (v)
|
||||
GenLocalAlloc(-v);
|
||||
GenGrowStack(-v);
|
||||
break;
|
||||
|
||||
case '(':
|
||||
@@ -2759,8 +2776,7 @@ void GenExpr0(void)
|
||||
#endif
|
||||
GenPrintInstr1Operand(X86InstrCall, 0,
|
||||
X86OpRegAWord, 0);
|
||||
if (v)
|
||||
GenLocalAlloc(-v);
|
||||
GenGrowStack(-v);
|
||||
break;
|
||||
|
||||
case tokUnaryStar:
|
||||
@@ -3318,6 +3334,109 @@ void GenFin(void)
|
||||
puts2(CodeFooter);
|
||||
}
|
||||
|
||||
#ifndef NO_STRUCT_BY_VAL
|
||||
if (StructPushLabel)
|
||||
{
|
||||
char s[1 + 2 + (2 + CHAR_BIT * sizeof StructPushLabel) / 3];
|
||||
char *p = s + sizeof s;
|
||||
|
||||
*--p = '\0';
|
||||
p = lab2str(p, StructPushLabel);
|
||||
*--p = '_';
|
||||
*--p = '_';
|
||||
|
||||
if (OutputFormat != FormatFlat)
|
||||
puts2(CodeHeader);
|
||||
|
||||
GenLabel(p, 1);
|
||||
GenFxnProlog();
|
||||
|
||||
if (SizeOfWord == 2)
|
||||
{
|
||||
puts2("\tmov\tdx, [bp+2]\n" // dx = return address
|
||||
"\tmov\tsi, [bp+4]\n" // si = &struct
|
||||
"\tmov\tcx, [bp+6]\n" // cx = sizeof(struct)
|
||||
"\tmov\tbp, [bp]\n" // restore bp
|
||||
|
||||
"\tmov\tax, cx\n" // ax = sizeof(struct)
|
||||
"\tinc\tax\n" // ax = sizeof(struct) + 1
|
||||
"\tand\tax, -2\n" // ax = sizeof(struct) rounded up to multiple of 2 bytes
|
||||
"\tadd\tsp, 4*2\n" // remove bp, return address and 2 args from stack
|
||||
"\tsub\tsp, ax"); // allocate stack space for struct
|
||||
|
||||
puts2("\tmov\tdi, sp\n" // di = where struct should be copied to
|
||||
"\tcld\n"
|
||||
"\trep\tmovsb\n" // copy
|
||||
|
||||
"\tpop\tax\n" // return first 2 bytes of struct in ax
|
||||
"\tpush\tax\n"
|
||||
"\tpush\tbyte 0\n" // caller will remove this 0 and first 2 bytes of struct from stack (as 2 args)
|
||||
"\tpush\tdx\n" // and then it will push ax (first 2 bytes of struct) back
|
||||
"\tret"); // actually return to return address saved in dx
|
||||
}
|
||||
#ifdef CAN_COMPILE_32BIT
|
||||
else if (OutputFormat != FormatSegHuge)
|
||||
{
|
||||
// Copying the pushed structure to the stack backwards
|
||||
// (from higher to lower addresses) in order to correctly
|
||||
// grow the stack on Windows, page by page
|
||||
puts2("\tmov\tedx, [ebp+4]\n" // edx = return address
|
||||
"\tmov\tesi, [ebp+8]\n" // esi = &struct
|
||||
"\tmov\tecx, [ebp+12]\n" // ecx = sizeof(struct)
|
||||
"\tmov\tebp, [ebp]\n" // restore ebp
|
||||
|
||||
"\tlea\teax, [ecx + 3]\n" // eax = sizeof(struct) + 3
|
||||
"\tand\teax, -4\n" // eax = sizeof(struct) rounded up to multiple of 4 bytes
|
||||
"\tadd\tesp, 4*4\n" // remove ebp, return address and 2 args from stack
|
||||
"\tsub\tesp, eax"); // allocate stack space for struct
|
||||
|
||||
puts2("\tlea\tesi, [esi + ecx - 1]\n" // esi = &last byte of struct
|
||||
"\tlea\tedi, [esp + ecx - 1]\n" // edi = where it should be copied to
|
||||
"\tstd\n"
|
||||
"\trep\tmovsb\n" // copy
|
||||
"\tcld\n"
|
||||
|
||||
"\tmov\teax, [esp]\n" // return first 4 bytes of struct in eax
|
||||
"\tpush\t0\n" // caller will remove this 0 and first 4 bytes of struct from stack (as 2 args)
|
||||
"\tpush\tedx\n" // and then it will push eax (first 4 bytes of struct) back
|
||||
"\tret"); // actually return to return address saved in edx
|
||||
}
|
||||
else
|
||||
{
|
||||
puts2("\tmov\tedx, [ebp+4]\n" // edx = return address (seg:ofs)
|
||||
"\tmov\tesi, [ebp+8]\n" // esi = &struct (phys)
|
||||
"\tror\tesi, 4\n"
|
||||
"\tmov\tds, si\n"
|
||||
"\tshr\tesi, 28\n" // ds:si = &struct (seg:ofs)
|
||||
"\tmov\tecx, [ebp+12]\n" // ecx = sizeof(struct)
|
||||
"\tmov\tebp, [ebp]\n" // restore ebp
|
||||
|
||||
"\tlea\teax, [ecx + 3]\n" // eax = sizeof(struct) + 3
|
||||
"\tand\teax, -4\n" // eax = sizeof(struct) rounded up to multiple of 4 bytes
|
||||
"\tadd\tsp, 4*4\n" // remove ebp, return address and 2 args from stack
|
||||
"\tsub\tsp, ax"); // allocate stack space for struct
|
||||
|
||||
puts2("\tmov\tax, ss\n"
|
||||
"\tmov\tes, ax\n" // es = ss
|
||||
"\tmov\tdi, sp\n" // es:di = where struct should be copied to (seg:ofs)
|
||||
"\tcld\n"
|
||||
"\trep\tmovsb\n" // copy; limit to ~64KB since stack size itself is ~64KB max
|
||||
|
||||
"\tpop\teax\n" // return first 4 bytes of struct in eax
|
||||
"\tpush\teax\n"
|
||||
"\tpush\teax\n" // caller will remove this and first 4 bytes of struct from stack (as 2 args)
|
||||
"\tpush\tedx\n" // and then it will push eax (first 4 bytes of struct) back
|
||||
"\tretf"); // actually return to return address saved in edx
|
||||
}
|
||||
#endif
|
||||
|
||||
// GenFxnEpilog();
|
||||
|
||||
if (OutputFormat != FormatFlat)
|
||||
puts2(CodeFooter);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SWITCH_TAB
|
||||
if (SwitchJmpLabel)
|
||||
{
|
||||
@@ -3477,4 +3596,3 @@ void GenFin(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2012-2014, Alexey Frunze
|
||||
Copyright (c) 2012-2015, Alexey Frunze
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -35,6 +35,7 @@ either expressed or implied, of the FreeBSD Project.
|
||||
/* */
|
||||
/* Produces 16/32-bit 80386 assembly output for NASM. */
|
||||
/* Produces 32-bit MIPS assembly output for gcc/as. */
|
||||
/* Produces 32-bit TR3200 assembly output for vasm. */
|
||||
/* */
|
||||
/* Main file */
|
||||
/* */
|
||||
@@ -55,6 +56,20 @@ either expressed or implied, of the FreeBSD Project.
|
||||
#define NO_FUNC_
|
||||
#define NO_EXTRA_WARNS
|
||||
#define NO_FOR_DECL
|
||||
#define NO_STRUCT_BY_VAL
|
||||
#endif
|
||||
|
||||
// Passing and returning structures by value is currenly supported
|
||||
// on x86 only
|
||||
#ifdef MIPS
|
||||
#ifndef NO_STRUCT_BY_VAL
|
||||
#define NO_STRUCT_BY_VAL
|
||||
#endif
|
||||
#endif
|
||||
#ifdef TR3200
|
||||
#ifndef NO_STRUCT_BY_VAL
|
||||
#define NO_STRUCT_BY_VAL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef __SMALLER_C__
|
||||
@@ -404,12 +419,14 @@ void GenJumpIfEqual(int val, int Label);
|
||||
STATIC
|
||||
void GenFxnProlog(void);
|
||||
STATIC
|
||||
void GenFxnProlog2(void);
|
||||
STATIC
|
||||
void GenFxnEpilog(void);
|
||||
void GenIsrProlog(void);
|
||||
void GenIsrEpilog(void);
|
||||
|
||||
STATIC
|
||||
void GenLocalAlloc(int Size);
|
||||
int GenMaxLocalsSize(void);
|
||||
|
||||
STATIC
|
||||
unsigned GenStrData(int generatingCode, unsigned requiredLen);
|
||||
@@ -631,21 +648,20 @@ int SizeOfWord = 2; // in chars (char can be a multiple of octets); ints and poi
|
||||
// TBD??? implement a function to allocate N labels with overflow checks
|
||||
int LabelCnt = 1; // label counter for jumps
|
||||
int StructCpyLabel = 0; // label of the function to copy structures/unions
|
||||
int StructPushLabel = 0; // label of the function to push structures/unions onto the stack
|
||||
|
||||
// call stack (from higher to lower addresses):
|
||||
// param n
|
||||
// arg n
|
||||
// ...
|
||||
// param 1
|
||||
// arg 1
|
||||
// return address
|
||||
// saved xbp register
|
||||
// local var 1
|
||||
// ...
|
||||
// local var n
|
||||
int CurFxnSyntaxPtr = 0;
|
||||
int CurFxnParamCnt = 0;
|
||||
int CurFxnParamCntMin = 0;
|
||||
int CurFxnParamCntMax = 0;
|
||||
int CurFxnParamOfs = 0; // positive
|
||||
int CurFxnLocalOfs = 0; // negative
|
||||
int CurFxnMinLocalOfs = 0; // negative
|
||||
|
||||
@@ -2173,7 +2189,11 @@ int GetToken(void)
|
||||
#endif
|
||||
#include "cgmips.c"
|
||||
#else
|
||||
#ifdef TR3200
|
||||
#include "cgtr3k2.c"
|
||||
#else
|
||||
#include "cgx86.c"
|
||||
#endif // #ifdef TR3200
|
||||
#endif // #ifdef MIPS
|
||||
|
||||
// expr.c code
|
||||
@@ -3106,6 +3126,26 @@ void simplifyConstExpr(int val, int isConst, int* ExprTypeSynPtr, int top, int b
|
||||
del(bottom, top - bottom);
|
||||
}
|
||||
|
||||
STATIC
|
||||
int AllocLocal(unsigned size)
|
||||
{
|
||||
// Let's calculate variable's relative on-stack location
|
||||
int oldOfs = CurFxnLocalOfs;
|
||||
|
||||
// Note: local vars are word-aligned on the stack
|
||||
CurFxnLocalOfs = uint2int((CurFxnLocalOfs - size) & ~(SizeOfWord - 1u));
|
||||
if (CurFxnLocalOfs >= oldOfs ||
|
||||
CurFxnLocalOfs != truncInt(CurFxnLocalOfs) ||
|
||||
CurFxnLocalOfs < -GenMaxLocalsSize())
|
||||
//error("AllocLocal(): Local variables take too much space\n");
|
||||
errorVarSize();
|
||||
|
||||
if (CurFxnMinLocalOfs > CurFxnLocalOfs)
|
||||
CurFxnMinLocalOfs = CurFxnLocalOfs;
|
||||
|
||||
return CurFxnLocalOfs;
|
||||
}
|
||||
|
||||
// DONE: sizeof(type)
|
||||
// DONE: "sizeof expr"
|
||||
// DONE: constant expressions
|
||||
@@ -3253,7 +3293,7 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
|
||||
break;
|
||||
default:
|
||||
#ifdef CAN_COMPILE_32BIT
|
||||
if (castSize && castSize != SizeOfWord && -castSize != SizeOfWord)
|
||||
if (castSize && castSize != SizeOfWord)
|
||||
{
|
||||
if (castSize == 2)
|
||||
{
|
||||
@@ -3269,7 +3309,7 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
|
||||
s -= 0x10000;
|
||||
}
|
||||
}
|
||||
else
|
||||
else // fallthrough
|
||||
#endif
|
||||
{
|
||||
// cast to int/unsigned/pointer
|
||||
@@ -4006,45 +4046,142 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
|
||||
int tmpSynPtr, c;
|
||||
int minParams, maxParams;
|
||||
int firstParamSynPtr;
|
||||
#ifndef NO_STRUCT_BY_VAL
|
||||
int oldIdx, oldSp;
|
||||
unsigned structSize = 0;
|
||||
int retStruct = 0;
|
||||
int retOfs = 0;
|
||||
#endif
|
||||
exprval(idx, ExprTypeSynPtr, ConstExpr);
|
||||
|
||||
if (!GetFxnInfo(*ExprTypeSynPtr, &minParams, &maxParams, ExprTypeSynPtr, &firstParamSynPtr))
|
||||
//error("exprval(): function or function pointer expected\n");
|
||||
errorOpType();
|
||||
|
||||
// DONE: validate the number of function parameters
|
||||
// DONE: warnings on int<->pointer substitution in params
|
||||
// DONE: validate the number of function arguments
|
||||
// DONE: warnings on int<->pointer substitution in params/args
|
||||
|
||||
// evaluate function parameters
|
||||
#ifndef NO_STRUCT_BY_VAL
|
||||
// If a structure is returned, allocate space for it on the stack
|
||||
// and pass its location as the first (implicit) argument.
|
||||
if (ParseLevel &&
|
||||
*ExprTypeSynPtr >= 0 &&
|
||||
SyntaxStack[*ExprTypeSynPtr][0] == tokStructPtr)
|
||||
{
|
||||
unsigned sz = GetDeclSize(*ExprTypeSynPtr, 0);
|
||||
// Make sure the return structure type is complete
|
||||
if (!sz)
|
||||
errorOpType();
|
||||
retOfs = AllocLocal(sz);
|
||||
// Transform fxn(args) into fxn(pretval, args)
|
||||
ins(*idx + 1, ',');
|
||||
ins2(*idx + 1, tokLocalOfs, retOfs);
|
||||
retStruct = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// evaluate function arguments
|
||||
c = 0;
|
||||
while (stack[*idx][0] != '(')
|
||||
{
|
||||
// add a comma after the first (last to be pushed) parameter,
|
||||
// so all parameters can be pushed whenever a comma is encountered
|
||||
#ifndef NO_STRUCT_BY_VAL
|
||||
int gotStructs;
|
||||
#endif
|
||||
// add a comma after the first (last to be pushed) argument,
|
||||
// so all arguments can be pushed whenever a comma is encountered
|
||||
if (!c)
|
||||
ins(*idx + 1, ',');
|
||||
|
||||
#ifndef NO_STRUCT_BY_VAL
|
||||
oldIdx = *idx;
|
||||
oldSp = sp;
|
||||
#endif
|
||||
exprval(idx, &tmpSynPtr, ConstExpr);
|
||||
//error("exprval(): function parameters cannot be of type 'void'\n");
|
||||
//error("exprval(): function arguments cannot be of type 'void'\n");
|
||||
|
||||
#ifdef NO_STRUCT_BY_VAL
|
||||
scalarTypeCheck(tmpSynPtr);
|
||||
#else
|
||||
nonVoidTypeCheck(tmpSynPtr);
|
||||
|
||||
// If the argument is a structure, push it by calling a dedicated function
|
||||
gotStructs = tmpSynPtr >= 0 && SyntaxStack[tmpSynPtr][0] == tokStructPtr;
|
||||
if (gotStructs)
|
||||
{
|
||||
unsigned sz = GetDeclSize(tmpSynPtr, 0);
|
||||
int i = oldIdx - (oldSp - sp);
|
||||
stack[i][0] = ')';
|
||||
stack[i][1] = SizeOfWord * 2;
|
||||
|
||||
if (!StructPushLabel)
|
||||
StructPushLabel = LabelCnt++;
|
||||
|
||||
// The code generator expects functions to return values.
|
||||
// If a function argument is a value produced by another function,
|
||||
// as is the case here, the code generator will naturally
|
||||
// want/need to push something of the size of the machine word.
|
||||
// This works perfectly with non-structures.
|
||||
// But we only want to push the structure without pushing any other words.
|
||||
// In order to avoid involving changes in the code generator,
|
||||
// we make the function that pushes structures onto the stack
|
||||
// push all words but the first one. The dedicated function will
|
||||
// return this word and the code generator will push it.
|
||||
// This is ugly.
|
||||
|
||||
ins2(i, tokIdent, AddNumericIdent__(StructPushLabel));
|
||||
ins(i, ',');
|
||||
i = *idx + 1;
|
||||
ins(i, ',');
|
||||
ins2(i, tokNumUint, uint2int(sz));
|
||||
ins2(i, '(', SizeOfWord * 2);
|
||||
|
||||
if (sz > (unsigned)GenMaxLocalsSize())
|
||||
errorVarSize();
|
||||
// Structures will be padded to machine word boundary when pushed
|
||||
sz = (sz + SizeOfWord - 1) & ~(SizeOfWord - 1u);
|
||||
// Count the cumulative size of the pushed structures, excluding
|
||||
// the first words that will be pushed by the code generator
|
||||
if (structSize + sz < structSize)
|
||||
errorVarSize();
|
||||
structSize += sz - SizeOfWord;
|
||||
if (structSize > (unsigned)GenMaxLocalsSize())
|
||||
errorVarSize();
|
||||
// TBD??? complete overflow checks (an expression may contain more than one call)?
|
||||
}
|
||||
#endif
|
||||
|
||||
if (++c > maxParams)
|
||||
error("Too many function parameters\n");
|
||||
error("Too many function arguments\n");
|
||||
|
||||
#ifndef NO_STRUCT_BY_VAL
|
||||
#ifndef CHECK_FXN_ARGS
|
||||
#define CHECK_FXN_ARGS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NO_EXTRA_WARNS
|
||||
// Issue a warning if the parameter has to be a pointer but isn't and vice versa.
|
||||
#ifndef CHECK_FXN_ARGS
|
||||
#define CHECK_FXN_ARGS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CHECK_FXN_ARGS
|
||||
// Issue a warning if the argument has to be a pointer but isn't and vice versa.
|
||||
// DONE: struct type compat checks
|
||||
// TBD??? Compare pointer types deeply as in compatCheck()???
|
||||
// TBD??? Issue a similar warning for return values and initializers???
|
||||
if (c <= minParams)
|
||||
{
|
||||
int t;
|
||||
#ifndef NO_EXTRA_WARNS
|
||||
int gotPtr = tmpSynPtr < 0;
|
||||
int needPtr;
|
||||
int t;
|
||||
if (!gotPtr)
|
||||
{
|
||||
t = SyntaxStack[tmpSynPtr][0];
|
||||
gotPtr = (t == '*') | (t == '[') | (t == '('); // arrays and functions decay to pointers
|
||||
}
|
||||
#endif
|
||||
// Find the type of the formal parameter in the function declaration
|
||||
while ((t = SyntaxStack[firstParamSynPtr][0]) != tokIdent)
|
||||
{
|
||||
@@ -4061,6 +4198,17 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
|
||||
firstParamSynPtr++;
|
||||
}
|
||||
firstParamSynPtr++;
|
||||
#ifndef NO_STRUCT_BY_VAL
|
||||
gotStructs += (SyntaxStack[firstParamSynPtr][0] == tokStructPtr) * 2;
|
||||
if (gotStructs)
|
||||
{
|
||||
// Structures must be of the same type
|
||||
if (gotStructs != 3 ||
|
||||
SyntaxStack[tmpSynPtr][1] != SyntaxStack[firstParamSynPtr][1])
|
||||
errorOpType();
|
||||
}
|
||||
#endif
|
||||
#ifndef NO_EXTRA_WARNS
|
||||
needPtr = SyntaxStack[firstParamSynPtr][0] == '*';
|
||||
if (needPtr != gotPtr &&
|
||||
// Make an exception for integer constants equal to 0, treat them as NULL pointers
|
||||
@@ -4070,9 +4218,10 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
|
||||
!stack[*idx + 1][1]
|
||||
)
|
||||
)
|
||||
warning("Expected %spointer in parameter %d\n", needPtr ? "" : "non-", c);
|
||||
warning("Expected %spointer in argument %d\n", needPtr ? "" : "non-", c);
|
||||
#endif
|
||||
}
|
||||
#endif // NO_EXTRA_WARNS
|
||||
#endif // CHECK_FXN_ARGS
|
||||
|
||||
if (stack[*idx][0] == ',')
|
||||
--*idx;
|
||||
@@ -4080,10 +4229,31 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
|
||||
--*idx;
|
||||
|
||||
if (c < minParams)
|
||||
error("Too few function parameters\n");
|
||||
error("Too few function arguments\n");
|
||||
|
||||
// store the cumulative parameter size in the function call operators
|
||||
stack[1 + *idx][1] = stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = c * SizeOfWord;
|
||||
// store the cumulative argument size in the function call operators
|
||||
{
|
||||
int i = oldIdxRight + 1 - (oldSpRight - sp);
|
||||
#ifndef NO_STRUCT_BY_VAL
|
||||
// Count the implicit param/arg for returned structure
|
||||
c += retStruct;
|
||||
#endif
|
||||
stack[1 + *idx][1] = stack[i][1] = c * SizeOfWord;
|
||||
#ifndef NO_STRUCT_BY_VAL
|
||||
// Correct the value by which the stack pointer
|
||||
// will be incremented after the call
|
||||
stack[i][1] += structSize;
|
||||
// If a structure is returned, transform
|
||||
// fxn(pretval, args) into *(fxn(pretval, args), pretval)
|
||||
if (retStruct)
|
||||
{
|
||||
ins(i + 1, tokUnaryStar);
|
||||
ins(i + 1, tokComma);
|
||||
ins2(i + 1, tokLocalOfs, retOfs);
|
||||
ins(i + 1, tokVoid);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
*ConstExpr = 0;
|
||||
}
|
||||
@@ -4093,6 +4263,7 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
|
||||
case tokComma:
|
||||
{
|
||||
int oldIdxLeft, oldSpLeft;
|
||||
int retStruct = 0;
|
||||
s = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]);
|
||||
oldIdxLeft = *idx;
|
||||
oldSpLeft = sp;
|
||||
@@ -4103,6 +4274,8 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
|
||||
exprval(idx, ExprTypeSynPtr, &constExpr[0]);
|
||||
*ConstExpr = constExpr[0] && constExpr[1];
|
||||
*ExprTypeSynPtr = RightExprTypeSynPtr;
|
||||
retStruct = RightExprTypeSynPtr >= 0 && SyntaxStack[RightExprTypeSynPtr][0] == tokStructPtr;
|
||||
|
||||
if (*ConstExpr)
|
||||
{
|
||||
// both subexprs are const, remove both and comma
|
||||
@@ -4110,10 +4283,27 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
|
||||
}
|
||||
else if (constExpr[0])
|
||||
{
|
||||
// only left subexpr is const, remove it and comma
|
||||
// only left subexpr is const, remove it
|
||||
del(*idx + 1, oldIdxLeft - (oldSpLeft - sp) - *idx);
|
||||
|
||||
if (!retStruct)
|
||||
// Ensure non-lvalue-ness of the result by changing comma to unary plus
|
||||
// and thus hiding dereference, if any
|
||||
stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUnaryPlus;
|
||||
else
|
||||
// However, (something, struct).member should still be allowed,
|
||||
// so, comma needs to produce lvalue
|
||||
del(oldIdxRight + 1 - (oldSpRight - sp), 1);
|
||||
}
|
||||
else if (retStruct)
|
||||
{
|
||||
// However, (something, struct).member should still be allowed,
|
||||
// so, comma needs to produce lvalue. Swap comma and structure dereference.
|
||||
int i = oldIdxRight + 1 - (oldSpRight - sp);
|
||||
stack[i][0] = tokUnaryStar;
|
||||
stack[i][1] = stack[i - 1][1];
|
||||
stack[i - 1][0] = tokComma;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -4322,8 +4512,7 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr)
|
||||
--*idx;
|
||||
exprval(idx, ExprTypeSynPtr, ConstExpr);
|
||||
|
||||
if (*ExprTypeSynPtr >= 0 && SyntaxStack[*ExprTypeSynPtr][0] == '*')
|
||||
*ExprTypeSynPtr = -(*ExprTypeSynPtr + 1); // TBD!!! shouldn't this be done elsewhere?
|
||||
decayArray(ExprTypeSynPtr, 0);
|
||||
|
||||
if (*ExprTypeSynPtr >= 0 ||
|
||||
SyntaxStack[-*ExprTypeSynPtr][0] != tokStructPtr)
|
||||
@@ -4393,6 +4582,9 @@ STATIC
|
||||
int ParseExpr(int tok, int* GotUnary, int* ExprTypeSynPtr, int* ConstExpr, int* ConstVal, int option, int option2)
|
||||
{
|
||||
int identFirst = tok == tokIdent;
|
||||
#ifndef NO_STRUCT_BY_VAL
|
||||
int oldOfs = CurFxnLocalOfs;
|
||||
#endif
|
||||
*ConstVal = *ConstExpr = 0;
|
||||
*ExprTypeSynPtr = SymVoidSynPtr;
|
||||
|
||||
@@ -4544,6 +4736,11 @@ int ParseExpr(int tok, int* GotUnary, int* ExprTypeSynPtr, int* ConstExpr, int*
|
||||
}
|
||||
|
||||
ExprLevel--;
|
||||
#ifndef NO_STRUCT_BY_VAL
|
||||
// Reclaim stack space used by temporary structure/union objects
|
||||
// returned by functions
|
||||
CurFxnLocalOfs = oldOfs;
|
||||
#endif
|
||||
|
||||
return tok;
|
||||
}
|
||||
@@ -4570,7 +4767,7 @@ void DetermineVaListType(void)
|
||||
char testbuf[3][CHAR_BIT * sizeof(void*) + 1];
|
||||
|
||||
// TBD!!! This is not good. Really need the va_something macros.
|
||||
// Test whether va_list is a pointer to the first optional parameter or
|
||||
// Test whether va_list is a pointer to the first optional argument or
|
||||
// an array of one element containing said pointer
|
||||
testptr[0] = &testptr[1];
|
||||
testptr[1] = &testptr[0];
|
||||
@@ -5576,7 +5773,7 @@ int ParseBase(int tok, int base[2])
|
||||
}
|
||||
else if (ParamLevel)
|
||||
{
|
||||
// structure/union/enum declarations aren't supported in function parameters
|
||||
// new structure/union/enum declarations aren't supported in function parameters
|
||||
errorDecl();
|
||||
}
|
||||
|
||||
@@ -5595,7 +5792,7 @@ int ParseBase(int tok, int base[2])
|
||||
{
|
||||
unsigned structInfo[4], sz, alignment, tmp;
|
||||
|
||||
// structure/union/enum declarations aren't supported in expressions and function parameters
|
||||
// new structure/union/enum declarations aren't supported in expressions and function parameters
|
||||
if (ExprLevel || ParamLevel)
|
||||
errorDecl();
|
||||
|
||||
@@ -6378,11 +6575,13 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label)
|
||||
|
||||
isFxn = SyntaxStack[lastSyntaxPtr + 1][0] == '(';
|
||||
|
||||
#ifdef NO_STRUCT_BY_VAL
|
||||
if (isFxn &&
|
||||
SyntaxStack[SyntaxStackCnt - 1][0] == tokStructPtr &&
|
||||
SyntaxStack[SyntaxStackCnt - 2][0] == ')')
|
||||
// structure returning isn't supported currently
|
||||
errorDecl();
|
||||
#endif
|
||||
|
||||
isArray = SyntaxStack[lastSyntaxPtr + 1][0] == '[';
|
||||
isIncompleteArr = isArray && SyntaxStack[lastSyntaxPtr + 2][1] == 0;
|
||||
@@ -6734,26 +6933,9 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label)
|
||||
|
||||
if (isLocal)
|
||||
{
|
||||
int oldOfs;
|
||||
// Let's calculate variable's relative on-stack location
|
||||
oldOfs = CurFxnLocalOfs;
|
||||
|
||||
// Note: local vars are word-aligned on the stack
|
||||
CurFxnLocalOfs = uint2int((CurFxnLocalOfs + 0u - sz) & ~(SizeOfWord - 1u));
|
||||
if (CurFxnLocalOfs >= oldOfs || CurFxnLocalOfs != truncInt(CurFxnLocalOfs))
|
||||
//error("ParseDecl(): Local variables take too much space\n");
|
||||
errorVarSize();
|
||||
#ifdef CAN_COMPILE_32BIT
|
||||
if (OutputFormat == FormatSegHuge && CurFxnLocalOfs < -0x7FFF)
|
||||
errorVarSize();
|
||||
#endif
|
||||
|
||||
// Now that the size of the local is certainly known,
|
||||
// update its offset in the offset token
|
||||
SyntaxStack[lastSyntaxPtr + 1][1] = CurFxnLocalOfs;
|
||||
|
||||
if (CurFxnMinLocalOfs > CurFxnLocalOfs)
|
||||
CurFxnMinLocalOfs = CurFxnLocalOfs;
|
||||
SyntaxStack[lastSyntaxPtr + 1][1] = AllocLocal(sz);
|
||||
|
||||
#ifndef NO_ANNOTATIONS
|
||||
DumpDecl(lastSyntaxPtr, 0);
|
||||
@@ -6808,6 +6990,7 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label)
|
||||
// Since a local integer variable always takes as much space as a whole int,
|
||||
// we can optimize code generation a bit by storing the initializer as an int.
|
||||
// This is an old accidental optimization and I preserve it for now.
|
||||
// Note, this implies a little-endian CPU.
|
||||
stack[sp - 1][1] = SizeOfWord;
|
||||
}
|
||||
|
||||
@@ -6841,6 +7024,14 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label)
|
||||
ParseLevel++;
|
||||
GetFxnInfo(lastSyntaxPtr, &CurFxnParamCntMin, &CurFxnParamCntMax, &CurFxnReturnExprTypeSynPtr, NULL); // get return type
|
||||
|
||||
#ifndef NO_STRUCT_BY_VAL
|
||||
// Make sure the return structure type is complete
|
||||
if (CurFxnReturnExprTypeSynPtr >= 0 &&
|
||||
SyntaxStack[CurFxnReturnExprTypeSynPtr][0] == tokStructPtr &&
|
||||
!GetDeclSize(CurFxnReturnExprTypeSynPtr, 0))
|
||||
errorDecl();
|
||||
#endif
|
||||
|
||||
if (OutputFormat != FormatFlat)
|
||||
puts2(CodeHeader);
|
||||
|
||||
@@ -6913,8 +7104,7 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label)
|
||||
GenFxnEpilog();
|
||||
|
||||
GenNumLabel(locAllocLabel + 1);
|
||||
if (CurFxnMinLocalOfs)
|
||||
GenLocalAlloc(-CurFxnMinLocalOfs);
|
||||
GenFxnProlog2();
|
||||
GenJumpUncond(locAllocLabel);
|
||||
if (OutputFormat != FormatFlat)
|
||||
puts2(CodeFooter);
|
||||
@@ -7061,11 +7251,13 @@ void ParseFxnParams(int tok)
|
||||
errorUnexpectedVoid();
|
||||
}
|
||||
|
||||
#ifdef NO_STRUCT_BY_VAL
|
||||
if (SyntaxStack[SyntaxStackCnt - 1][0] == tokStructPtr &&
|
||||
t != '*' &&
|
||||
t != ']')
|
||||
// structure passing and returning isn't supported currently
|
||||
errorDecl();
|
||||
#endif
|
||||
|
||||
if (tok == ')')
|
||||
break;
|
||||
@@ -7083,6 +7275,7 @@ STATIC
|
||||
void AddFxnParamSymbols(int SyntaxPtr)
|
||||
{
|
||||
int i;
|
||||
unsigned paramOfs = 2 * SizeOfWord; // ret addr, xbp
|
||||
|
||||
if (SyntaxPtr < 0 ||
|
||||
SyntaxPtr > SyntaxStackCnt - 3 ||
|
||||
@@ -7092,11 +7285,29 @@ void AddFxnParamSymbols(int SyntaxPtr)
|
||||
errorInternal(6);
|
||||
|
||||
CurFxnSyntaxPtr = SyntaxPtr;
|
||||
CurFxnParamCnt = 0;
|
||||
CurFxnParamOfs = 2 * SizeOfWord; // ret addr, xbp
|
||||
CurFxnLocalOfs = 0;
|
||||
CurFxnMinLocalOfs = 0;
|
||||
|
||||
#ifndef NO_STRUCT_BY_VAL
|
||||
if (CurFxnReturnExprTypeSynPtr >= 0 &&
|
||||
SyntaxStack[CurFxnReturnExprTypeSynPtr][0] == tokStructPtr)
|
||||
{
|
||||
// The function returns a struct/union via an implicit param/arg (pointer to struct/union)
|
||||
// before its first formal param/arg, add this implicit param/arg
|
||||
#ifndef NO_ANNOTATIONS
|
||||
int paramPtr = SyntaxStackCnt;
|
||||
#endif
|
||||
PushSyntax2(tokIdent, AddIdent("@")); // special implicit param/arg (pretval) pointing to structure receptacle
|
||||
PushSyntax2(tokLocalOfs, paramOfs);
|
||||
PushSyntax('*');
|
||||
PushSyntax2(tokStructPtr, SyntaxStack[CurFxnReturnExprTypeSynPtr][1]);
|
||||
paramOfs += SizeOfWord;
|
||||
#ifndef NO_ANNOTATIONS
|
||||
DumpDecl(paramPtr, 0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
SyntaxPtr += 2; // skip "ident("
|
||||
|
||||
for (i = SyntaxPtr; i < SyntaxStackCnt; i++)
|
||||
@@ -7105,7 +7316,7 @@ void AddFxnParamSymbols(int SyntaxPtr)
|
||||
|
||||
if (tok == tokIdent)
|
||||
{
|
||||
int sz;
|
||||
unsigned sz;
|
||||
#ifndef NO_ANNOTATIONS
|
||||
int paramPtr;
|
||||
#endif
|
||||
@@ -7119,19 +7330,28 @@ void AddFxnParamSymbols(int SyntaxPtr)
|
||||
if (SyntaxStack[i + 1][0] == tokEllipsis) // "ident(something,...)" = no more params
|
||||
break;
|
||||
|
||||
// Make sure the parameter is not an incomplete structure
|
||||
sz = GetDeclSize(i, 0);
|
||||
if (sz == 0)
|
||||
//error("Internal error: AddFxnParamSymbols(): GetDeclSize() = 0\n");
|
||||
errorInternal(8);
|
||||
//errorInternal(8);
|
||||
errorDecl();
|
||||
|
||||
// Let's calculate this parameter's relative on-stack location
|
||||
CurFxnParamOfs = (CurFxnParamOfs + SizeOfWord - 1) / SizeOfWord * SizeOfWord;
|
||||
#ifndef NO_ANNOTATIONS
|
||||
paramPtr = SyntaxStackCnt;
|
||||
#endif
|
||||
PushSyntax2(SyntaxStack[i][0], SyntaxStack[i][1]);
|
||||
PushSyntax2(tokLocalOfs, CurFxnParamOfs);
|
||||
CurFxnParamOfs += sz;
|
||||
PushSyntax2(tokLocalOfs, paramOfs);
|
||||
|
||||
if (sz + SizeOfWord - 1 < sz)
|
||||
errorVarSize();
|
||||
sz = (sz + SizeOfWord - 1) & ~(SizeOfWord - 1u);
|
||||
if (paramOfs + sz < paramOfs)
|
||||
errorVarSize();
|
||||
paramOfs += sz;
|
||||
if (paramOfs > (unsigned)GenMaxLocalsSize())
|
||||
errorVarSize();
|
||||
|
||||
// Duplicate this parameter in the symbol table
|
||||
i++;
|
||||
@@ -7140,7 +7360,6 @@ void AddFxnParamSymbols(int SyntaxPtr)
|
||||
tok = SyntaxStack[i][0];
|
||||
if (tok == tokIdent || tok == ')')
|
||||
{
|
||||
CurFxnParamCnt++;
|
||||
#ifndef NO_ANNOTATIONS
|
||||
DumpDecl(paramPtr, 0);
|
||||
#endif
|
||||
@@ -7269,10 +7488,77 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx)
|
||||
errorUnexpectedToken(tok);
|
||||
if (gotUnary)
|
||||
//error("ParseStatement(): cannot return a value of type 'void'\n");
|
||||
#ifdef NO_STRUCT_BY_VAL
|
||||
scalarTypeCheck(synPtr);
|
||||
#else
|
||||
nonVoidTypeCheck(synPtr);
|
||||
#endif
|
||||
}
|
||||
if (gotUnary)
|
||||
{
|
||||
#ifndef NO_STRUCT_BY_VAL
|
||||
int structs = (synPtr >= 0 && SyntaxStack[synPtr][0] == tokStructPtr) +
|
||||
(CurFxnReturnExprTypeSynPtr >= 0 && SyntaxStack[CurFxnReturnExprTypeSynPtr][0] == tokStructPtr) * 2;
|
||||
|
||||
if (structs)
|
||||
{
|
||||
if (structs != 3 ||
|
||||
SyntaxStack[synPtr][1] != SyntaxStack[CurFxnReturnExprTypeSynPtr][1])
|
||||
errorOpType();
|
||||
|
||||
// Transform "return *pstruct" into structure assignment ("*pretval = *pstruct")
|
||||
// via function call "fxn(sizeof *pretval, pstruct, pretval)".
|
||||
|
||||
// There are a couple of differences to how this is implemented in the assignment operator:
|
||||
// - the structure dereference has already been dropped from *pstruct by ParseExpr(),
|
||||
// so it isn't removed here
|
||||
// - we don't add the structure dereference on top of the value returned by "fxn()"
|
||||
// because the return statement is not an expression that can be an operand into another
|
||||
// operator
|
||||
|
||||
ins(0, ',');
|
||||
ins2(0, tokUnaryStar, SizeOfWord); // dereference to extract the implicit param/arg (pretval) from the stack
|
||||
ins2(0, tokLocalOfs, SyntaxStack[FindSymbol("@") + 1][1]); // special implicit param/arg (pretval) pointing to structure receptacle
|
||||
ins2(0, '(', SizeOfWord * 3);
|
||||
push(',');
|
||||
push2(tokNumUint, GetDeclSize(synPtr, 0));
|
||||
push(',');
|
||||
if (!StructCpyLabel)
|
||||
StructCpyLabel = LabelCnt++;
|
||||
push2(tokIdent, AddNumericIdent__(StructCpyLabel));
|
||||
push2(')', SizeOfWord * 3);
|
||||
}
|
||||
else // fallthrough
|
||||
#endif
|
||||
{
|
||||
// If return value (per function declaration) is a scalar type smaller than machine word,
|
||||
// properly zero- or sign-extend the returned value to machine word size.
|
||||
// TBD??? Move this cast to the caller?
|
||||
int castSize = GetDeclSize(CurFxnReturnExprTypeSynPtr, 1);
|
||||
if (castSize != SizeOfWord &&
|
||||
(synPtr < 0 || castSize != GetDeclSize(synPtr, 1)))
|
||||
{
|
||||
switch (castSize)
|
||||
{
|
||||
case 1:
|
||||
push(tokUChar);
|
||||
break;
|
||||
case -1:
|
||||
push(tokSChar);
|
||||
break;
|
||||
#ifdef CAN_COMPILE_32BIT
|
||||
case 2:
|
||||
push(tokUShort);
|
||||
break;
|
||||
case -2:
|
||||
push(tokShort);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
GenExpr();
|
||||
}
|
||||
GenJumpUncond(CurFxnEpilogLabel);
|
||||
tok = GetToken();
|
||||
}
|
||||
@@ -7572,7 +7858,7 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx)
|
||||
GenNumLabel(labelAfter);
|
||||
|
||||
#ifndef NO_FOR_DECL
|
||||
// undo any declarations done in the for() parameter set.
|
||||
// undo any declarations made in the first clause of for
|
||||
if (decl)
|
||||
{
|
||||
UndoNonLabelIdents(undoIdents); // remove all identifier names, except those of labels
|
||||
@@ -7931,7 +8217,7 @@ int main(int argc, char** argv)
|
||||
|
||||
GenInit();
|
||||
|
||||
// Parse the command line parameters
|
||||
// Parse the command line arguments
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
// DONE: move code-generator-specific options to
|
||||
|
||||
Reference in New Issue
Block a user