Created a stream output system.

Implemented sprintf().

git-svn-id: http://picoc.googlecode.com/svn/trunk@271 21eae674-98b7-11dd-bd71-f92a316d2d60
This commit is contained in:
zik.saleeba 2009-04-27 04:56:58 +00:00
parent 647cc90999
commit b6e61dd8ab
6 changed files with 122 additions and 52 deletions

1
TODO
View file

@ -27,6 +27,7 @@ Improvements:
* expression and auto-cast support for all types * expression and auto-cast support for all types
* periodic heap cleanup * periodic heap cleanup
* octal/hex character constants * octal/hex character constants
* comma expressions
* see if we can use ParserCopyPos() in other places rather than copying everything * see if we can use ParserCopyPos() in other places rather than copying everything
* check for no value returned in functions with a return value * check for no value returned in functions with a return value
* native pointer access? * native pointer access?

View file

@ -1,5 +1,7 @@
#include "picoc.h" #include "picoc.h"
struct OutputStream CStdOut;
static int TRUEValue = 1; static int TRUEValue = 1;
static int ZeroValue = 0; static int ZeroValue = 0;
@ -14,6 +16,8 @@ void LibraryInit(struct Table *GlobalTable, const char *LibraryName, struct Libr
void *Tokens; void *Tokens;
const char *IntrinsicName = TableStrRegister("c library"); const char *IntrinsicName = TableStrRegister("c library");
CStdOut.Putch = &PlatformPutc;
for (Count = 0; (*FuncList)[Count].Prototype != NULL; Count++) for (Count = 0; (*FuncList)[Count].Prototype != NULL; Count++)
{ {
Tokens = LexAnalyse(IntrinsicName, (*FuncList)[Count].Prototype, strlen((char *)(*FuncList)[Count].Prototype), NULL); Tokens = LexAnalyse(IntrinsicName, (*FuncList)[Count].Prototype, strlen((char *)(*FuncList)[Count].Prototype), NULL);
@ -34,15 +38,30 @@ void CLibraryInit()
VariableDefinePlatformVar(NULL, "FALSE", &IntType, (union AnyValue *)&ZeroValue, FALSE); VariableDefinePlatformVar(NULL, "FALSE", &IntType, (union AnyValue *)&ZeroValue, FALSE);
} }
/* stream for writing into strings */
void SPutc(unsigned char Ch, union OutputStreamInfo *Stream)
{
struct StringOutputStream *Out = &Stream->Str;
*Out->WritePos++ = Ch;
if (Out->WritePos == Out->MaxPos)
Out->WritePos--;
}
/* print a character to a stream without using printf/sprintf */
void PrintCh(char OutCh, struct OutputStream *Stream)
{
(*Stream->Putch)(OutCh, &Stream->i);
}
/* print a string to a stream without using printf/sprintf */ /* print a string to a stream without using printf/sprintf */
void PrintStr(const char *Str, CharWriter *PutCh) void PrintStr(const char *Str, struct OutputStream *Stream)
{ {
while (*Str != 0) while (*Str != 0)
PutCh(*Str++); PrintCh(*Str++, Stream);
} }
/* print an integer to a stream without using printf/sprintf */ /* print an integer to a stream without using printf/sprintf */
void PrintInt(int Num, CharWriter *PutCh) void PrintInt(int Num, struct OutputStream *Stream)
{ {
int Div; int Div;
int Remainder = 0; int Remainder = 0;
@ -50,12 +69,12 @@ void PrintInt(int Num, CharWriter *PutCh)
if (Num < 0) if (Num < 0)
{ {
PutCh('-'); PrintCh('-', Stream);
Num = -Num; Num = -Num;
} }
if (Num == 0) if (Num == 0)
PutCh('0'); PrintCh('0', Stream);
else else
{ {
Div = LARGE_INT_POWER_OF_TEN; Div = LARGE_INT_POWER_OF_TEN;
@ -64,7 +83,7 @@ void PrintInt(int Num, CharWriter *PutCh)
Remainder = Num / Div; Remainder = Num / Div;
if (Printing || Remainder > 0) if (Printing || Remainder > 0)
{ {
PutCh('0' + Remainder); PrintCh('0' + Remainder, Stream);
Printing = TRUE; Printing = TRUE;
} }
Num -= Remainder * Div; Num -= Remainder * Div;
@ -75,7 +94,7 @@ void PrintInt(int Num, CharWriter *PutCh)
#ifndef NO_FP #ifndef NO_FP
/* print a double to a stream without using printf/sprintf */ /* print a double to a stream without using printf/sprintf */
void PrintFP(double Num, CharWriter *PutCh) void PrintFP(double Num, struct OutputStream *Stream)
{ {
int Exponent = 0; int Exponent = 0;
@ -85,42 +104,42 @@ void PrintFP(double Num, CharWriter *PutCh)
Exponent = log(Num) / LOG10E - 0.999999999; Exponent = log(Num) / LOG10E - 0.999999999;
Num /= pow(10.0, Exponent); Num /= pow(10.0, Exponent);
PrintInt((int)Num, PutCh); PrintInt((int)Num, Stream);
PutCh('.'); PrintCh('.', Stream);
for (Num -= (int)Num; Num != 0.0; Num *= 10.0) for (Num -= (int)Num; Num != 0.0; Num *= 10.0)
PutCh('0' + (int)Num); PrintCh('0' + (int)Num, Stream);
if (Exponent) if (Exponent)
{ {
PutCh('e'); PrintCh('e', Stream);
PrintInt(Exponent, PutCh); PrintInt(Exponent, Stream);
} }
} }
#endif #endif
/* print a type to a stream without using printf/sprintf */ /* print a type to a stream without using printf/sprintf */
void PrintType(struct ValueType *Typ, CharWriter *PutCh) void PrintType(struct ValueType *Typ, struct OutputStream *Stream)
{ {
switch (Typ->Base) switch (Typ->Base)
{ {
case TypeVoid: PrintStr("void", PutCh); break; case TypeVoid: PrintStr("void", Stream); break;
case TypeInt: PrintStr("int", PutCh); break; case TypeInt: PrintStr("int", Stream); break;
#ifndef NO_FP #ifndef NO_FP
case TypeFP: PrintStr("double", PutCh); break; case TypeFP: PrintStr("double", Stream); break;
#endif #endif
case TypeChar: PrintStr("char", PutCh); break; case TypeChar: PrintStr("char", Stream); break;
case TypeFunction: PrintStr("function", PutCh); break; case TypeFunction: PrintStr("function", Stream); break;
case TypeMacro: PrintStr("macro", PutCh); break; case TypeMacro: PrintStr("macro", Stream); break;
case TypePointer: if (Typ->FromType) PrintType(Typ->FromType, PutCh); PutCh('*'); break; case TypePointer: if (Typ->FromType) PrintType(Typ->FromType, Stream); PrintCh('*', Stream); break;
case TypeArray: PrintType(Typ->FromType, PutCh); PutCh('['); if (Typ->ArraySize != 0) PrintInt(Typ->ArraySize, PutCh); PutCh(']'); break; case TypeArray: PrintType(Typ->FromType, Stream); PrintCh('[', Stream); if (Typ->ArraySize != 0) PrintInt(Typ->ArraySize, Stream); PrintCh(']', Stream); break;
case TypeStruct: PrintStr("struct ", PutCh); PrintStr(Typ->Identifier, PutCh); break; case TypeStruct: PrintStr("struct ", Stream); PrintStr(Typ->Identifier, Stream); break;
case TypeUnion: PrintStr("union ", PutCh); PrintStr(Typ->Identifier, PutCh); break; case TypeUnion: PrintStr("union ", Stream); PrintStr(Typ->Identifier, Stream); break;
case TypeEnum: PrintStr("enum ", PutCh); PrintStr(Typ->Identifier, PutCh); break; case TypeEnum: PrintStr("enum ", Stream); PrintStr(Typ->Identifier, Stream); break;
} }
} }
/* intrinsic functions made available to the language */ /* intrinsic functions made available to the language */
void LibPrintf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) void GenericPrintf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs, struct OutputStream *Stream)
{ {
struct Value *CharArray = Param[0]->Val->Pointer.Segment; struct Value *CharArray = Param[0]->Val->Pointer.Segment;
char *Format; char *Format;
@ -146,20 +165,20 @@ void LibPrintf(struct ParseState *Parser, struct Value *ReturnValue, struct Valu
#ifndef NO_FP #ifndef NO_FP
case 'f': FormatType = &FPType; break; case 'f': FormatType = &FPType; break;
#endif #endif
case '%': PlatformPutc('%'); FormatType = NULL; break; case '%': PrintCh('%', Stream); FormatType = NULL; break;
case '\0': FPos--; FormatType = NULL; break; case '\0': FPos--; FormatType = NULL; break;
default: PlatformPutc(*FPos); FormatType = NULL; break; default: PrintCh(*FPos, Stream); FormatType = NULL; break;
} }
if (FormatType != NULL) if (FormatType != NULL)
{ /* we have to format something */ { /* we have to format something */
if (ArgCount >= NumArgs) if (ArgCount >= NumArgs)
PrintStr("XXX", PlatformPutc); /* not enough parameters for format */ PrintStr("XXX", Stream); /* not enough parameters for format */
else else
{ {
NextArg = (struct Value *)((void *)NextArg + sizeof(struct Value) + TypeStackSizeValue(NextArg)); NextArg = (struct Value *)((void *)NextArg + sizeof(struct Value) + TypeStackSizeValue(NextArg));
if (NextArg->Typ != FormatType && !(FormatType == &IntType && IS_INTEGER_COERCIBLE(NextArg))) if (NextArg->Typ != FormatType && !(FormatType == &IntType && IS_INTEGER_COERCIBLE(NextArg)))
PrintStr("XXX", PlatformPutc); /* bad type for format */ PrintStr("XXX", Stream); /* bad type for format */
else else
{ {
switch (*FPos) switch (*FPos)
@ -174,13 +193,13 @@ void LibPrintf(struct ParseState *Parser, struct Value *ReturnValue, struct Valu
else else
Str = CharArray->Val->Array.Data + NextArg->Val->Pointer.Offset; Str = CharArray->Val->Array.Data + NextArg->Val->Pointer.Offset;
PrintStr(Str, PlatformPutc); PrintStr(Str, Stream);
break; break;
} }
case 'd': PrintInt(COERCE_INTEGER(NextArg), PlatformPutc); break; case 'd': PrintInt(COERCE_INTEGER(NextArg), Stream); break;
case 'c': PlatformPutc(COERCE_INTEGER(NextArg)); break; case 'c': PrintCh(COERCE_INTEGER(NextArg), Stream); break;
#ifndef NO_FP #ifndef NO_FP
case 'f': PrintFP(NextArg->Val->FP, PlatformPutc); break; case 'f': PrintFP(NextArg->Val->FP, Stream); break;
#endif #endif
} }
} }
@ -190,10 +209,40 @@ void LibPrintf(struct ParseState *Parser, struct Value *ReturnValue, struct Valu
} }
} }
else else
PlatformPutc(*FPos); PrintCh(*FPos, Stream);
} }
} }
/* printf(): print to console output */
void LibPrintf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
struct OutputStream ConsoleStream;
ConsoleStream.Putch = &PlatformPutc;
GenericPrintf(Parser, ReturnValue, Param, NumArgs, &ConsoleStream);
}
/* sprintf(): print to a string */
void LibSPrintf(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{
struct OutputStream StrStream;
struct Value *DerefVal;
int DerefOffset;
struct ValueType *DerefType;
StrStream.i.Str.WritePos = VariableDereferencePointer(StrStream.i.Str.Parser, Param[0], &DerefVal, &DerefOffset, &DerefType);
if (DerefVal->Typ->Base != TypeArray)
ProgramFail(Parser, "can only print to arrays of char");
StrStream.Putch = &SPutc;
StrStream.i.Str.Parser = Parser;
StrStream.i.Str.MaxPos = StrStream.i.Str.WritePos- DerefOffset + DerefVal->Val->Array.Size;
GenericPrintf(Parser, ReturnValue, Param+1, NumArgs-1, &StrStream);
PrintCh(0, &StrStream);
ReturnValue->Val->Pointer.Segment = *Param;
ReturnValue->Val->Pointer.Offset = 0;
}
/* get a line of input. protected from buffer overrun */ /* get a line of input. protected from buffer overrun */
void LibGets(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) void LibGets(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs)
{ {
@ -202,7 +251,7 @@ void LibGets(struct ParseState *Parser, struct Value *ReturnValue, struct Value
int MaxLength = CharArray->Val->Array.Size - Param[0]->Val->Pointer.Offset; int MaxLength = CharArray->Val->Array.Size - Param[0]->Val->Pointer.Offset;
char *Result; char *Result;
ReturnValue->Val->Pointer.Segment = 0; ReturnValue->Val->Pointer.Segment = NULL;
ReturnValue->Val->Pointer.Offset = 0; ReturnValue->Val->Pointer.Offset = 0;
if (Param[0]->Val->Pointer.Offset < 0 || MaxLength < 0) if (Param[0]->Val->Pointer.Offset < 0 || MaxLength < 0)
@ -224,6 +273,7 @@ void LibGetc(struct ParseState *Parser, struct Value *ReturnValue, struct Value
struct LibraryFunction CLibrary[] = struct LibraryFunction CLibrary[] =
{ {
{ LibPrintf, "void printf(char *, ...)" }, { LibPrintf, "void printf(char *, ...)" },
{ LibSPrintf, "char *sprintf(char *, char *, ...)" },
{ LibGets, "void gets(char *, int)" }, { LibGets, "void gets(char *, int)" },
{ LibGetc, "int getchar()" }, { LibGetc, "int getchar()" },
{ NULL, NULL } { NULL, NULL }

34
picoc.h
View file

@ -231,8 +231,26 @@ struct LibraryFunction
const char *Prototype; const char *Prototype;
}; };
/* platform-specific method for writing characters to the console */ /* output stream-type specific state information */
typedef void CharWriter(unsigned char); union OutputStreamInfo
{
struct StringOutputStream
{
struct ParseState *Parser;
char *WritePos;
char *MaxPos;
} Str;
};
/* stream-specific method for writing characters to the console */
typedef void CharWriter(unsigned char, union OutputStreamInfo *);
/* used when writing output to a string - eg. sprintf() */
struct OutputStream
{
CharWriter *Putch;
union OutputStreamInfo i;
};
/* globals */ /* globals */
extern void *HeapStackTop; extern void *HeapStackTop;
@ -253,6 +271,7 @@ extern char *StrEmpty;
extern struct PointerValue NULLPointer; extern struct PointerValue NULLPointer;
extern struct LibraryFunction CLibrary[]; extern struct LibraryFunction CLibrary[];
extern struct LibraryFunction PlatformLibrary[]; extern struct LibraryFunction PlatformLibrary[];
extern struct OutputStream CStdOut;
/* table.c */ /* table.c */
void TableInit(); void TableInit();
@ -335,10 +354,11 @@ void *VariableDereferencePointer(struct ParseState *Parser, struct Value *Pointe
/* clibrary.c */ /* clibrary.c */
void LibraryInit(struct Table *GlobalTable, const char *LibraryName, struct LibraryFunction (*FuncList)[]); void LibraryInit(struct Table *GlobalTable, const char *LibraryName, struct LibraryFunction (*FuncList)[]);
void CLibraryInit(); void CLibraryInit();
void PrintInt(int Num, CharWriter *PutCh); void PrintCh(char OutCh, struct OutputStream *Stream);
void PrintStr(const char *Str, CharWriter *PutCh); void PrintInt(int Num, struct OutputStream *Stream);
void PrintFP(double Num, CharWriter *PutCh); void PrintStr(const char *Str, struct OutputStream *Stream);
void PrintType(struct ValueType *Typ, CharWriter *PutCh); void PrintFP(double Num, struct OutputStream *Stream);
void PrintType(struct ValueType *Typ, struct OutputStream *Stream);
/* platform.c */ /* platform.c */
void ProgramFail(struct ParseState *Parser, const char *Message, ...); void ProgramFail(struct ParseState *Parser, const char *Message, ...);
@ -347,7 +367,7 @@ void PlatformCleanup();
void PlatformScanFile(const char *FileName); void PlatformScanFile(const char *FileName);
char *PlatformGetLine(char *Buf, int MaxLen); char *PlatformGetLine(char *Buf, int MaxLen);
int PlatformGetCharacter(); int PlatformGetCharacter();
void PlatformPutc(unsigned char OutCh); void PlatformPutc(unsigned char OutCh, union OutputStreamInfo *);
void PlatformPrintf(const char *Format, ...); void PlatformPrintf(const char *Format, ...);
void PlatformVPrintf(const char *Format, va_list Args); void PlatformVPrintf(const char *Format, va_list Args);
void PlatformExit(); void PlatformExit();

View file

@ -1,6 +1,5 @@
#include "picoc.h" #include "picoc.h"
/* exit with a message */ /* exit with a message */
void ProgramFail(struct ParseState *Parser, const char *Message, ...) void ProgramFail(struct ParseState *Parser, const char *Message, ...)
{ {
@ -50,18 +49,18 @@ void PlatformVPrintf(const char *Format, va_list Args)
FPos++; FPos++;
switch (*FPos) switch (*FPos)
{ {
case 's': PrintStr(va_arg(Args, char *), PlatformPutc); break; case 's': PrintStr(va_arg(Args, char *), &CStdOut); break;
case 'd': PrintInt(va_arg(Args, int), PlatformPutc); break; case 'd': PrintInt(va_arg(Args, int), &CStdOut); break;
case 'c': PlatformPutc(va_arg(Args, int)); break; case 'c': PrintCh(va_arg(Args, int), &CStdOut); break;
case 't': PrintType(va_arg(Args, struct ValueType *), PlatformPutc); break; case 't': PrintType(va_arg(Args, struct ValueType *), &CStdOut); break;
#ifndef NO_FP #ifndef NO_FP
case 'f': PrintFP(va_arg(Args, double), PlatformPutc); break; case 'f': PrintFP(va_arg(Args, double), &CStdOut); break;
#endif #endif
case '%': PlatformPutc('%'); break; case '%': PrintCh('%', &CStdOut); break;
case '\0': FPos--; break; case '\0': FPos--; break;
} }
} }
else else
PlatformPutc(*FPos); PrintCh(*FPos, &CStdOut);
} }
} }

View file

@ -32,7 +32,7 @@ char *PlatformGetLine(char *Buf, int MaxLen)
} }
/* write a character to the console */ /* write a character to the console */
void PlatformPutc(unsigned char OutCh) void PlatformPutc(unsigned char OutCh, union OutputStreamInfo *Stream)
{ {
putchar(OutCh); putchar(OutCh);
} }

View file

@ -25,7 +25,7 @@ int PlatformGetCharacter()
} }
/* write a character to the console */ /* write a character to the console */
void PlatformPutc(unsigned char OutCh) void PlatformPutc(unsigned char OutCh, union OutputStreamInfo *Stream)
{ {
putchar(OutCh); putchar(OutCh);
} }