Added some more comments.

Added the beginnings of a debugger. It's not useful yet.


git-svn-id: http://picoc.googlecode.com/svn/trunk@570 21eae674-98b7-11dd-bd71-f92a316d2d60
This commit is contained in:
zik.saleeba 2011-05-01 06:50:00 +00:00
parent 0bb912af5d
commit 853b6f6259
16 changed files with 250 additions and 31 deletions

View file

@ -4,7 +4,7 @@ LIBS=-lm -lreadline
TARGET = picoc
SRCS = picoc.c table.c lex.c parse.c expression.c heap.c type.c \
variable.c clibrary.c platform.c include.c \
variable.c clibrary.c platform.c include.c debug.c \
platform/platform_unix.c platform/library_unix.c \
cstdlib/stdio.c cstdlib/math.c cstdlib/string.c cstdlib/stdlib.c \
cstdlib/time.c cstdlib/errno.c cstdlib/ctype.c cstdlib/stdbool.c \
@ -24,7 +24,7 @@ clean:
count:
@echo "Core:"
@cat picoc.h interpreter.h picoc.c table.c lex.c parse.c expression.c platform.c heap.c type.c variable.c include.c | grep -v '^[ ]*/\*' | grep -v '^[ ]*$$' | wc
@cat picoc.h interpreter.h picoc.c table.c lex.c parse.c expression.c platform.c heap.c type.c variable.c include.c debug.c | grep -v '^[ ]*/\*' | grep -v '^[ ]*$$' | wc
@echo ""
@echo "Everything:"
@cat $(SRCS) *.h */*.h | wc
@ -42,6 +42,7 @@ variable.o: variable.c interpreter.h platform.h
clibrary.o: clibrary.c picoc.h interpreter.h platform.h
platform.o: platform.c picoc.h interpreter.h platform.h
include.o: include.c picoc.h interpreter.h platform.h
debug.o: debug.c interpreter.h platform.h
platform/platform_unix.o: platform/platform_unix.c picoc.h interpreter.h platform.h
platform/library_unix.o: platform/library_unix.c interpreter.h platform.h
cstdlib/stdio.o: cstdlib/stdio.c interpreter.h platform.h

View file

@ -1,3 +1,6 @@
/* picoc mini standard C library - provides an optional tiny C standard library
* if BUILTIN_MINI_STDLIB is defined */
#include "picoc.h"
#include "interpreter.h"
@ -35,13 +38,13 @@ void LibraryAdd(struct Table *GlobalTable, const char *LibraryName, struct Libra
struct ValueType *ReturnType;
struct Value *NewValue;
void *Tokens;
const char *IntrinsicName = TableStrRegister("c library");
char *IntrinsicName = TableStrRegister("c library");
/* read all the library definitions */
for (Count = 0; FuncList[Count].Prototype != NULL; Count++)
{
Tokens = LexAnalyse(IntrinsicName, FuncList[Count].Prototype, strlen((char *)FuncList[Count].Prototype), NULL);
LexInitParser(&Parser, FuncList[Count].Prototype, Tokens, IntrinsicName, TRUE);
LexInitParser(&Parser, FuncList[Count].Prototype, Tokens, IntrinsicName, TRUE, FALSE);
TypeParse(&Parser, &ReturnType, &Identifier, NULL);
NewValue = ParseFunctionDefinition(&Parser, ReturnType, Identifier);
NewValue->Val->FuncDef.Intrinsic = FuncList[Count].Func;

127
debug.c Normal file
View file

@ -0,0 +1,127 @@
/* picoc interactive debugger */
#ifndef NO_DEBUGGER
#include "interpreter.h"
#define BREAKPOINT_TABLE_SIZE 21
#define BREAKPOINT_HASH(p) ( ((unsigned long)(p)->FileName) ^ (((p)->Line << 16) | ((p)->CharacterPos << 16)) )
struct Table BreakpointTable;
struct TableEntry *BreakpointHashTable[BREAKPOINT_TABLE_SIZE];
int BreakpointCount = 0;
int DebugManualBreak = FALSE;
/* initialise the debugger by clearing the breakpoint table */
void DebugInit()
{
TableInitTable(&BreakpointTable, &BreakpointHashTable[0], BREAKPOINT_TABLE_SIZE, TRUE);
BreakpointCount = 0;
}
/* free the contents of the breakpoint table */
void DebugCleanup()
{
struct TableEntry *Entry;
struct TableEntry *NextEntry;
int Count;
for (Count = 0; Count < BreakpointTable.Size; Count++)
{
for (Entry = BreakpointHashTable[Count]; Entry != NULL; Entry = NextEntry)
{
NextEntry = Entry->Next;
HeapFreeMem(Entry);
}
}
}
/* search the table for a breakpoint */
static struct TableEntry *DebugTableSearchBreakpoint(struct ParseState *Parser, int *AddAt)
{
struct TableEntry *Entry;
int HashValue = BREAKPOINT_HASH(Parser) % BreakpointTable.Size;
for (Entry = BreakpointHashTable[HashValue]; Entry != NULL; Entry = Entry->Next)
{
if (Entry->p.b.FileName == Parser->FileName && Entry->p.b.Line == Parser->Line && Entry->p.b.CharacterPos == Parser->CharacterPos)
return Entry; /* found */
}
*AddAt = HashValue; /* didn't find it in the chain */
return NULL;
}
/* set a breakpoint in the table */
void DebugSetBreakpoint(struct ParseState *Parser)
{
int AddAt;
struct TableEntry *FoundEntry = DebugTableSearchBreakpoint(Parser, &AddAt);
if (FoundEntry == NULL)
{
/* add it to the table */
struct TableEntry *NewEntry = HeapAllocMem(sizeof(struct TableEntry));
if (NewEntry == NULL)
ProgramFail(NULL, "out of memory");
NewEntry->p.b.FileName = Parser->FileName;
NewEntry->p.b.Line = Parser->Line;
NewEntry->p.b.CharacterPos = Parser->CharacterPos;
NewEntry->Next = BreakpointHashTable[AddAt];
BreakpointHashTable[AddAt] = NewEntry;
BreakpointCount++;
}
}
/* delete a breakpoint from the hash table */
int DebugClearBreakpoint(struct ParseState *Parser)
{
struct TableEntry **EntryPtr;
int HashValue = BREAKPOINT_HASH(Parser) % BreakpointTable.Size;
for (EntryPtr = &BreakpointHashTable[HashValue]; *EntryPtr != NULL; EntryPtr = &(*EntryPtr)->Next)
{
struct TableEntry *DeleteEntry = *EntryPtr;
if (DeleteEntry->p.b.FileName == Parser->FileName && DeleteEntry->p.b.Line == Parser->Line && DeleteEntry->p.b.CharacterPos == Parser->CharacterPos)
{
*EntryPtr = DeleteEntry->Next;
HeapFreeMem(DeleteEntry);
BreakpointCount--;
return TRUE;
}
}
return FALSE;
}
/* before we run a statement, check if there's anything we have to do with the debugger here */
void DebugCheckStatement(struct ParseState *Parser)
{
int DoBreak = FALSE;
int AddAt;
/* has the user manually pressed break? */
if (DebugManualBreak)
{
DoBreak = TRUE;
DebugManualBreak = FALSE;
}
/* is this a breakpoint location? */
if (BreakpointCount != 0 && DebugTableSearchBreakpoint(Parser, &AddAt) != NULL)
DoBreak = TRUE;
/* handle a break */
if (DoBreak)
{
PlatformPrintf("Handling a break\n");
PicocParseInteractiveNoStartPrompt(FALSE);
}
}
void DebugStep()
{
}
#endif /* !NO_DEBUGGER */

View file

@ -1,6 +1,8 @@
/* picoc expression evaluator - a stack-based expression evaluation system
* which handles operator precedence */
#include "interpreter.h"
/* whether evaluation is left to right for a given precedence level */
#define IS_LEFT_TO_RIGHT(p) ((p) != 2 && (p) != 14)
#define BRACKET_PRECEDENCE 20

4
heap.c
View file

@ -1,3 +1,7 @@
/* picoc heap memory allocation. This is a complete (but small) memory
* allocator for embedded systems which have no memory allocator. Alternatively
* you can define USE_MALLOC_HEAP to use your system's own malloc() allocator */
/* stack grows up from the bottom and heap grows down from the top of heap space */
#include "interpreter.h"

View file

@ -1,3 +1,6 @@
/* picoc include system - can emulate system includes from built-in libraries
* or it can include and parse files if the system has files */
#include "picoc.h"
#include "interpreter.h"
@ -92,7 +95,7 @@ void IncludeFile(char *FileName)
/* parse the setup C source code - may define types etc. */
if (LInclude->SetupCSource != NULL)
PicocParse(FileName, LInclude->SetupCSource, strlen(LInclude->SetupCSource), TRUE, TRUE, FALSE);
PicocParse(FileName, LInclude->SetupCSource, strlen(LInclude->SetupCSource), TRUE, TRUE, FALSE, FALSE);
/* set up the library functions */
if (LInclude->FuncList != NULL)

View file

@ -1,3 +1,7 @@
/* picoc main header file - this has all the main data structures and
* function prototypes. If you're just calling picoc you should look at the
* external interface instead, in picoc.h */
#ifndef INTERPRETER_H
#define INTERPRETER_H
@ -104,16 +108,17 @@ enum RunMode
/* parser state - has all this detail so we can parse nested files */
struct ParseState
{
const unsigned char *Pos;
const char *FileName;
short int Line;
short int CharacterPos;
const unsigned char *Pos; /* the character position in the source text */
char *FileName; /* what file we're executing (registered string) */
short int Line; /* line number we're executing */
short int CharacterPos; /* character/column in the line we're executing */
enum RunMode Mode; /* whether to skip or run code */
int SearchLabel; /* what case label we're searching for */
const char *SearchGotoLabel;/* what goto label we're searching for */
short int HashIfLevel;
short int HashIfEvaluateToLevel;
const char *SourceText;
const char *SourceText; /* the entire source text */
short int HashIfLevel; /* how many "if"s we're nested down */
short int HashIfEvaluateToLevel; /* if we're not evaluating an if branch, what the last evaluated level was */
char DebugMode; /* debugging mode */
};
/* values */
@ -225,6 +230,14 @@ struct TableEntry
} v; /* used for tables of values */
char Key[1]; /* dummy size - used for the shared string table */
struct BreakpointEntry /* defines a breakpoint */
{
const char *FileName;
short int Line;
short int CharacterPos;
} b;
} p;
};
@ -340,7 +353,7 @@ void TableStrFree();
void LexInit();
void LexCleanup();
void *LexAnalyse(const char *FileName, const char *Source, int SourceLen, int *TokenLen);
void LexInitParser(struct ParseState *Parser, const char *SourceText, void *TokenSource, const char *FileName, int RunIt);
void LexInitParser(struct ParseState *Parser, const char *SourceText, void *TokenSource, char *FileName, int RunIt, int SetDebugMode);
enum LexToken LexGetToken(struct ParseState *Parser, struct Value **Value, int IncPos);
enum LexToken LexRawPeekToken(struct ParseState *Parser);
void LexToEndOfLine(struct ParseState *Parser);
@ -353,6 +366,7 @@ void LexInteractiveStatementPrompt();
/* the following are defined in picoc.h:
* void PicocParse(const char *FileName, const char *Source, int SourceLen, int RunIt, int CleanupNow, int CleanupSource);
* void PicocParseInteractive(); */
void PicocParseInteractiveNoStartPrompt(int EnableDebugger);
enum ParseResult ParseStatement(struct ParseState *Parser, int CheckTrailingSemicolon);
struct Value *ParseFunctionDefinition(struct ParseState *Parser, struct ValueType *ReturnType, char *Identifier);
void ParseCleanup();
@ -440,6 +454,7 @@ void LibPrintf(struct ParseState *Parser, struct Value *ReturnValue, struct Valu
void ProgramFail(struct ParseState *Parser, const char *Message, ...);
void AssignFail(struct ParseState *Parser, const char *Format, struct ValueType *Type1, struct ValueType *Type2, int Num1, int Num2, const char *FuncName, int ParamNo);
void LexFail(struct LexState *Lexer, const char *Message, ...);
void PlatformInit();
void PlatformCleanup();
char *PlatformGetLine(char *Buf, int MaxLen, const char *Prompt);
int PlatformGetCharacter();
@ -458,6 +473,13 @@ void IncludeRegister(const char *IncludeName, void (*SetupFunction)(void), struc
void IncludeFile(char *Filename);
/* the following is defined in picoc.h:
* void PicocIncludeAllSystemHeaders(); */
/* debug.c */
extern int DebugManualBreak;
void DebugInit();
void DebugCleanup();
void DebugCheckStatement(struct ParseState *Parser);
/* stdio.c */
extern const char StdioDefs[];

5
lex.c
View file

@ -1,3 +1,5 @@
/* picoc lexer - converts source text into a tokenised form */
#include "interpreter.h"
#ifdef NO_CTYPE
@ -583,7 +585,7 @@ void *LexAnalyse(const char *FileName, const char *Source, int SourceLen, int *T
}
/* prepare to parse a pre-tokenised buffer */
void LexInitParser(struct ParseState *Parser, const char *SourceText, void *TokenSource, const char *FileName, int RunIt)
void LexInitParser(struct ParseState *Parser, const char *SourceText, void *TokenSource, char *FileName, int RunIt, int EnableDebugger)
{
Parser->Pos = TokenSource;
Parser->Line = 1;
@ -594,6 +596,7 @@ void LexInitParser(struct ParseState *Parser, const char *SourceText, void *Toke
Parser->HashIfEvaluateToLevel = 0;
Parser->CharacterPos = 0;
Parser->SourceText = SourceText;
Parser->DebugMode = EnableDebugger;
}
/* get the next token, without pre-processing */

26
parse.c
View file

@ -1,3 +1,5 @@
/* picoc parser - parses source and executes statements */
#include "picoc.h"
#include "interpreter.h"
@ -484,6 +486,11 @@ enum ParseResult ParseStatement(struct ParseState *Parser, int CheckTrailingSemi
struct ParseState PreState;
enum LexToken Token;
/* if we're debugging, check for a breakpoint */
if (Parser->DebugMode && Parser->Mode == RunModeRun)
DebugCheckStatement(Parser);
/* take note of where we are and then grab a token to see what statement we have */
ParserCopy(&PreState, Parser);
Token = LexGetToken(Parser, &LexerValue, TRUE);
@ -806,13 +813,14 @@ enum ParseResult ParseStatement(struct ParseState *Parser, int CheckTrailingSemi
}
/* quick scan a source file for definitions */
void PicocParse(const char *FileName, const char *Source, int SourceLen, int RunIt, int CleanupNow, int CleanupSource)
void PicocParse(const char *FileName, const char *Source, int SourceLen, int RunIt, int CleanupNow, int CleanupSource, int EnableDebugger)
{
struct ParseState Parser;
enum ParseResult Ok;
struct CleanupTokenNode *NewCleanupNode;
char *RegFileName = TableStrRegister(FileName);
void *Tokens = LexAnalyse(FileName, Source, SourceLen, NULL);
void *Tokens = LexAnalyse(RegFileName, Source, SourceLen, NULL);
/* allocate a cleanup node so we can clean up the tokens later */
if (!CleanupNow)
@ -832,7 +840,7 @@ void PicocParse(const char *FileName, const char *Source, int SourceLen, int Run
}
/* do the parsing */
LexInitParser(&Parser, Source, Tokens, FileName, RunIt);
LexInitParser(&Parser, Source, Tokens, RegFileName, RunIt, EnableDebugger);
do {
Ok = ParseStatement(&Parser, TRUE);
@ -847,13 +855,12 @@ void PicocParse(const char *FileName, const char *Source, int SourceLen, int Run
}
/* parse interactively */
void PicocParseInteractive()
void PicocParseInteractiveNoStartPrompt(int EnableDebugger)
{
struct ParseState Parser;
enum ParseResult Ok;
PlatformPrintf(INTERACTIVE_PROMPT_START);
LexInitParser(&Parser, NULL, NULL, StrEmpty, TRUE);
LexInitParser(&Parser, NULL, NULL, StrEmpty, TRUE, EnableDebugger);
PicocPlatformSetExitPoint();
LexInteractiveClear(&Parser);
@ -870,3 +877,10 @@ void PicocParseInteractive()
PlatformPrintf("\n");
}
/* parse interactively, showing a startup message */
void PicocParseInteractive()
{
PlatformPrintf(INTERACTIVE_PROMPT_START);
PicocParseInteractiveNoStartPrompt(TRUE);
}

View file

@ -1,3 +1,6 @@
/* picoc main program - this varies depending on your operating system and
* how you're using picoc */
/* include only picoc.h here - should be able to use it with only the external interfaces, no internals from interpreter.h */
#include "picoc.h"
@ -36,7 +39,7 @@ int main(int argc, char **argv)
if (argc > ParamCount && strcmp(argv[ParamCount], "-i") == 0)
{
PicocIncludeAllSystemHeaders();
PicocParseInteractive();
PicocParseInteractive(TRUE);
}
else
{

View file

@ -1,11 +1,13 @@
/* picoc external interface. This should be the only header you need to use if
* you're using picoc as a library. Internal details are in interpreter.h */
#ifndef PICOC_H
#define PICOC_H
/* picoc version number */
#ifdef VER
#define PICOC_VERSION "v2.1 beta r" VER /* VER is the subversion version number, obtained via the Makefile */
#define PICOC_VERSION "v2.2 beta r" VER /* VER is the subversion version number, obtained via the Makefile */
#else
#define PICOC_VERSION "v2.1 beta"
#define PICOC_VERSION "v2.2"
#endif
/* handy definitions */
@ -33,7 +35,7 @@ extern int PicocExitBuf[];
#endif
/* parse.c */
void PicocParse(const char *FileName, const char *Source, int SourceLen, int RunIt, int CleanupNow, int CleanupSource);
void PicocParse(const char *FileName, const char *Source, int SourceLen, int RunIt, int CleanupNow, int CleanupSource, int EnableDebugger);
void PicocParseInteractive();
/* platform.c */

View file

@ -1,3 +1,6 @@
/* picoc's interface to the underlying platform. most platform-specific code
* is in platform/platform_XX.c and platform/library_XX.c */
#include "picoc.h"
#include "interpreter.h"
@ -7,6 +10,7 @@ int PicocExitValue = 0;
/* initialise everything */
void PicocInitialise(int StackSize)
{
PlatformInit();
BasicIOInit();
HeapInit(StackSize);
TableInit();
@ -22,12 +26,13 @@ void PicocInitialise(int StackSize)
CLibraryInit();
#endif
PlatformLibraryInit();
DebugInit();
}
/* free memory */
void PicocCleanup()
{
PlatformCleanup();
DebugCleanup();
#ifndef NO_HASH_INCLUDE
IncludeCleanup();
#endif
@ -37,6 +42,7 @@ void PicocCleanup()
TypeCleanup();
TableStrFree();
HeapCleanup();
PlatformCleanup();
}
/* platform-dependent code for running programs */
@ -69,18 +75,18 @@ void PicocCallMain(int argc, char **argv)
if (FuncValue->Val->FuncDef.ReturnType == &VoidType)
{
if (FuncValue->Val->FuncDef.NumParams == 0)
PicocParse("startup", CALL_MAIN_NO_ARGS_RETURN_VOID, strlen(CALL_MAIN_NO_ARGS_RETURN_VOID), TRUE, TRUE, FALSE);
PicocParse("startup", CALL_MAIN_NO_ARGS_RETURN_VOID, strlen(CALL_MAIN_NO_ARGS_RETURN_VOID), TRUE, TRUE, FALSE, TRUE);
else
PicocParse("startup", CALL_MAIN_WITH_ARGS_RETURN_VOID, strlen(CALL_MAIN_WITH_ARGS_RETURN_VOID), TRUE, TRUE, FALSE);
PicocParse("startup", CALL_MAIN_WITH_ARGS_RETURN_VOID, strlen(CALL_MAIN_WITH_ARGS_RETURN_VOID), TRUE, TRUE, FALSE, TRUE);
}
else
{
VariableDefinePlatformVar(NULL, "__exit_value", &IntType, (union AnyValue *)&PicocExitValue, TRUE);
if (FuncValue->Val->FuncDef.NumParams == 0)
PicocParse("startup", CALL_MAIN_NO_ARGS_RETURN_INT, strlen(CALL_MAIN_NO_ARGS_RETURN_INT), TRUE, TRUE, FALSE);
PicocParse("startup", CALL_MAIN_NO_ARGS_RETURN_INT, strlen(CALL_MAIN_NO_ARGS_RETURN_INT), TRUE, TRUE, FALSE, TRUE);
else
PicocParse("startup", CALL_MAIN_WITH_ARGS_RETURN_INT, strlen(CALL_MAIN_WITH_ARGS_RETURN_INT), TRUE, TRUE, FALSE);
PicocParse("startup", CALL_MAIN_WITH_ARGS_RETURN_INT, strlen(CALL_MAIN_WITH_ARGS_RETURN_INT), TRUE, TRUE, FALSE, TRUE);
}
}
#endif

View file

@ -9,6 +9,26 @@
/* mark where to end the program for platforms which require this */
jmp_buf PicocExitBuf;
#ifndef NO_DEBUGGER
#include <signal.h>
static void BreakHandler(int Signal)
{
PlatformPrintf("break\n");
DebugManualBreak = TRUE;
}
void PlatformInit()
{
/* capture the break signal and pass it to the debugger */
signal(SIGINT, BreakHandler);
}
#else
void PlatformInit()
{
}
#endif
void PlatformCleanup()
{
}
@ -90,7 +110,7 @@ void PicocPlatformScanFile(const char *FileName)
{
char *SourceStr = PlatformReadFile(FileName);
PicocParse(FileName, SourceStr, strlen(SourceStr), TRUE, FALSE, TRUE);
PicocParse(FileName, SourceStr, strlen(SourceStr), TRUE, FALSE, TRUE, TRUE);
}
/* exit the program */

View file

@ -1,3 +1,6 @@
/* picoc hash table module. This hash table code is used for both symbol tables
* and the shared string table. */
#include "interpreter.h"
struct Table StringTable;

3
type.c
View file

@ -1,3 +1,6 @@
/* picoc data type module. This manages a tree of data types and has facilities
* for parsing data types. */
#include "interpreter.h"
/* some basic types */

View file

@ -1,3 +1,6 @@
/* picoc variable storage. This provides ways of defining and accessing
* variables */
#include "interpreter.h"
/* maximum size of a value to temporarily copy while we create a variable */