2008-12-26 23:36:45 -05:00
|
|
|
#include "picoc.h"
|
|
|
|
|
2009-02-24 05:29:14 -05:00
|
|
|
/* initialise a library */
|
2009-02-24 06:16:37 -05:00
|
|
|
void LibraryInit(struct Table *GlobalTable, const char *LibraryName, struct LibraryFunction (*FuncList)[])
|
2009-02-24 05:29:14 -05:00
|
|
|
{
|
|
|
|
struct ParseState Parser;
|
|
|
|
int Count;
|
|
|
|
char *Identifier;
|
|
|
|
struct ValueType *ReturnType;
|
|
|
|
struct Value *NewValue;
|
|
|
|
void *Tokens;
|
|
|
|
const char *IntrinsicName = TableStrRegister("c library");
|
|
|
|
|
2009-02-24 06:16:37 -05:00
|
|
|
for (Count = 0; (*FuncList)[Count].Prototype != NULL; Count++)
|
2009-02-24 05:29:14 -05:00
|
|
|
{
|
2009-04-03 23:11:12 -04:00
|
|
|
Tokens = LexAnalyse(IntrinsicName, (*FuncList)[Count].Prototype, strlen((char *)(*FuncList)[Count].Prototype), NULL);
|
2009-02-24 05:29:14 -05:00
|
|
|
LexInitParser(&Parser, Tokens, IntrinsicName, Count+1, TRUE);
|
|
|
|
TypeParse(&Parser, &ReturnType, &Identifier);
|
|
|
|
NewValue = ParseFunctionDefinition(&Parser, ReturnType, Identifier, TRUE);
|
2009-02-24 06:16:37 -05:00
|
|
|
NewValue->Val->FuncDef.Intrinsic = (*FuncList)[Count].Func;
|
2009-02-24 05:29:14 -05:00
|
|
|
HeapFree(Tokens);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-24 06:16:37 -05:00
|
|
|
/* print a string to a stream without using printf/sprintf */
|
|
|
|
void PrintStr(const char *Str, CharWriter *PutCh)
|
|
|
|
{
|
|
|
|
while (*Str != 0)
|
|
|
|
PutCh(*Str++);
|
|
|
|
}
|
|
|
|
|
2009-02-20 21:35:52 -05:00
|
|
|
/* print an integer to a stream without using printf/sprintf */
|
2009-02-24 06:16:37 -05:00
|
|
|
void PrintInt(int Num, CharWriter *PutCh)
|
2009-02-20 21:35:52 -05:00
|
|
|
{
|
|
|
|
int Div;
|
|
|
|
int Remainder = 0;
|
|
|
|
int Printing = FALSE;
|
|
|
|
|
|
|
|
if (Num < 0)
|
|
|
|
{
|
2009-02-24 06:16:37 -05:00
|
|
|
PutCh('-');
|
2009-02-20 21:35:52 -05:00
|
|
|
Num = -Num;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Num == 0)
|
2009-02-24 06:16:37 -05:00
|
|
|
PutCh('0');
|
2009-02-20 21:35:52 -05:00
|
|
|
else
|
|
|
|
{
|
|
|
|
Div = LARGE_INT_POWER_OF_TEN;
|
|
|
|
while (Div > 0)
|
|
|
|
{
|
|
|
|
Remainder = Num / Div;
|
|
|
|
if (Printing || Remainder > 0)
|
|
|
|
{
|
2009-02-24 06:16:37 -05:00
|
|
|
PutCh('0' + Remainder);
|
2009-02-20 21:35:52 -05:00
|
|
|
Printing = TRUE;
|
|
|
|
}
|
|
|
|
Num -= Remainder * Div;
|
|
|
|
Div /= 10;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-23 23:52:35 -05:00
|
|
|
#ifndef NO_FP
|
2009-02-20 21:35:52 -05:00
|
|
|
/* print a double to a stream without using printf/sprintf */
|
2009-02-24 06:16:37 -05:00
|
|
|
void PrintFP(double Num, CharWriter *PutCh)
|
2009-02-20 21:35:52 -05:00
|
|
|
{
|
|
|
|
int Exponent = 0;
|
|
|
|
|
|
|
|
if (abs(Num) >= 1e7)
|
|
|
|
Exponent = log(Num) / LOG10E;
|
|
|
|
else if (abs(Num) <= 1e-7)
|
|
|
|
Exponent = log(Num) / LOG10E - 0.999999999;
|
|
|
|
|
|
|
|
Num /= pow(10.0, Exponent);
|
2009-02-24 06:16:37 -05:00
|
|
|
PrintInt((int)Num, PutCh);
|
|
|
|
PutCh('.');
|
2009-02-20 21:35:52 -05:00
|
|
|
for (Num -= (int)Num; Num != 0.0; Num *= 10.0)
|
2009-02-24 06:16:37 -05:00
|
|
|
PutCh('0' + (int)Num);
|
2009-02-20 21:35:52 -05:00
|
|
|
|
|
|
|
if (Exponent)
|
|
|
|
{
|
2009-02-24 06:16:37 -05:00
|
|
|
PutCh('e');
|
|
|
|
PrintInt(Exponent, PutCh);
|
2009-02-20 21:35:52 -05:00
|
|
|
}
|
|
|
|
}
|
2009-02-23 23:52:35 -05:00
|
|
|
#endif
|
2009-02-20 21:35:52 -05:00
|
|
|
|
|
|
|
/* intrinsic functions made available to the language */
|
2009-02-28 17:14:55 -05:00
|
|
|
void LibPrintf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
|
2008-12-26 23:36:45 -05:00
|
|
|
{
|
2009-02-20 21:35:52 -05:00
|
|
|
struct Value *CharArray = Param[0]->Val->Pointer.Segment;
|
|
|
|
char *Format;
|
|
|
|
char *FPos;
|
|
|
|
struct Value *NextArg = Param[0];
|
|
|
|
struct ValueType *FormatType;
|
|
|
|
int ArgCount = 1;
|
|
|
|
|
2009-03-15 03:07:21 -04:00
|
|
|
if (Param[0]->Val->Pointer.Offset < 0 || Param[0]->Val->Pointer.Offset >= CharArray->Val->Array.Size)
|
2009-02-20 21:35:52 -05:00
|
|
|
Format = StrEmpty;
|
|
|
|
else
|
2009-03-15 03:07:21 -04:00
|
|
|
Format = CharArray->Val->Array.Data + Param[0]->Val->Pointer.Offset;
|
2009-02-20 21:35:52 -05:00
|
|
|
|
|
|
|
for (FPos = Format; *FPos != '\0'; FPos++)
|
|
|
|
{
|
|
|
|
if (*FPos == '%')
|
|
|
|
{
|
|
|
|
FPos++;
|
|
|
|
switch (*FPos)
|
|
|
|
{
|
|
|
|
case 's': FormatType = CharPtrType; break;
|
2009-02-23 19:21:17 -05:00
|
|
|
case 'd': case 'c': FormatType = &IntType; break;
|
|
|
|
#ifndef NO_FP
|
2009-02-20 21:35:52 -05:00
|
|
|
case 'f': FormatType = &FPType; break;
|
2009-02-23 19:21:17 -05:00
|
|
|
#endif
|
2009-02-24 06:16:37 -05:00
|
|
|
case '%': PlatformPutc('%'); FormatType = NULL; break;
|
2009-02-20 21:35:52 -05:00
|
|
|
case '\0': FPos--; FormatType = NULL; break;
|
2009-02-24 06:16:37 -05:00
|
|
|
default: PlatformPutc(*FPos); FormatType = NULL; break;
|
2009-02-20 21:35:52 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (FormatType != NULL)
|
|
|
|
{ /* we have to format something */
|
|
|
|
if (ArgCount >= NumArgs)
|
2009-02-24 06:16:37 -05:00
|
|
|
PrintStr("XXX", PlatformPutc); /* not enough parameters for format */
|
2009-02-20 21:35:52 -05:00
|
|
|
else
|
|
|
|
{
|
2009-03-02 17:13:47 -05:00
|
|
|
NextArg = (struct Value *)((void *)NextArg + sizeof(struct Value) + TypeStackSizeValue(NextArg));
|
2009-02-20 21:35:52 -05:00
|
|
|
if (NextArg->Typ != FormatType)
|
2009-02-24 06:16:37 -05:00
|
|
|
PrintStr("XXX", PlatformPutc); /* bad type for format */
|
2009-02-20 21:35:52 -05:00
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (*FPos)
|
|
|
|
{
|
|
|
|
case 's':
|
|
|
|
{
|
|
|
|
struct Value *CharArray = NextArg->Val->Pointer.Segment;
|
|
|
|
char *Str;
|
|
|
|
|
2009-03-15 03:07:21 -04:00
|
|
|
if (NextArg->Val->Pointer.Offset < 0 || NextArg->Val->Pointer.Offset >= CharArray->Val->Array.Size)
|
2009-02-20 21:35:52 -05:00
|
|
|
Str = StrEmpty;
|
|
|
|
else
|
2009-03-15 03:07:21 -04:00
|
|
|
Str = CharArray->Val->Array.Data + NextArg->Val->Pointer.Offset;
|
2009-02-20 21:35:52 -05:00
|
|
|
|
2009-02-24 06:16:37 -05:00
|
|
|
PrintStr(Str, PlatformPutc);
|
2009-02-20 21:35:52 -05:00
|
|
|
break;
|
|
|
|
}
|
2009-02-24 06:16:37 -05:00
|
|
|
case 'd': PrintInt(NextArg->Val->Integer, PlatformPutc); break;
|
|
|
|
case 'c': PlatformPutc(NextArg->Val->Integer); break;
|
2009-02-23 19:21:17 -05:00
|
|
|
#ifndef NO_FP
|
2009-02-24 06:16:37 -05:00
|
|
|
case 'f': PrintFP(NextArg->Val->FP, PlatformPutc); break;
|
2009-02-23 19:21:17 -05:00
|
|
|
#endif
|
2009-02-20 21:35:52 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ArgCount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2009-02-24 06:16:37 -05:00
|
|
|
PlatformPutc(*FPos);
|
2009-02-20 21:35:52 -05:00
|
|
|
}
|
2008-12-26 23:36:45 -05:00
|
|
|
}
|
|
|
|
|
2009-03-15 05:57:19 -04:00
|
|
|
/* get a line of input. protected from buffer overrun */
|
2009-03-15 03:07:21 -04:00
|
|
|
void LibGets(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
|
|
|
|
{
|
2009-03-15 05:57:19 -04:00
|
|
|
struct Value *CharArray = Param[0]->Val->Pointer.Segment;
|
|
|
|
char *ReadBuffer = CharArray->Val->Array.Data + Param[0]->Val->Pointer.Offset;
|
|
|
|
int MaxLength = CharArray->Val->Array.Size - Param[0]->Val->Pointer.Offset;
|
|
|
|
char *Result;
|
|
|
|
|
|
|
|
ReturnValue->Val->Pointer.Segment = 0;
|
|
|
|
ReturnValue->Val->Pointer.Offset = 0;
|
|
|
|
|
|
|
|
if (Param[0]->Val->Pointer.Offset < 0 || MaxLength < 0)
|
|
|
|
return; /* no room for data */
|
|
|
|
|
|
|
|
Result = PlatformGetLine(ReadBuffer, MaxLength);
|
|
|
|
if (Result == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ReturnValue->Val->Pointer = Param[0]->Val->Pointer;
|
2009-03-15 03:07:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void LibGetc(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
|
|
|
|
{
|
2009-03-15 05:57:19 -04:00
|
|
|
ReturnValue->Val->Integer = PlatformGetCharacter();
|
2009-03-15 03:07:21 -04:00
|
|
|
}
|
|
|
|
|
2009-02-24 06:16:37 -05:00
|
|
|
/* list of all library functions and their prototypes */
|
|
|
|
struct LibraryFunction CLibrary[] =
|
2008-12-26 23:36:45 -05:00
|
|
|
{
|
2009-02-24 06:16:37 -05:00
|
|
|
{ LibPrintf, "void printf(char *, ...)" },
|
2009-03-15 03:07:21 -04:00
|
|
|
{ LibGets, "void gets(char *, int)" },
|
2009-03-15 05:57:19 -04:00
|
|
|
{ LibGetc, "int getchar()" },
|
2009-02-24 06:16:37 -05:00
|
|
|
{ NULL, NULL }
|
2008-12-26 23:36:45 -05:00
|
|
|
};
|