Added test framework.
Implemented preprocessor-style directives (not finished yet). git-svn-id: http://picoc.googlecode.com/svn/trunk@26 21eae674-98b7-11dd-bd71-f92a316d2d60
This commit is contained in:
parent
939c68cd4d
commit
995266ce9c
3
Makefile
3
Makefile
|
@ -11,6 +11,9 @@ all: $(TARGET)
|
||||||
$(TARGET): $(OBJS)
|
$(TARGET): $(OBJS)
|
||||||
$(CC) $(CFLAGS) -o $(TARGET) $(OBJS) $(LIBS)
|
$(CC) $(CFLAGS) -o $(TARGET) $(OBJS) $(LIBS)
|
||||||
|
|
||||||
|
test: picoc
|
||||||
|
(cd test; make test)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(TARGET) $(OBJS) *~
|
rm -f $(TARGET) $(OBJS) *~
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,11 @@
|
||||||
|
|
||||||
Str IntrinsicFilename = { 9, "intrinsic" };
|
Str IntrinsicFilename = { 9, "intrinsic" };
|
||||||
|
|
||||||
|
void IntrinsicPrintInt(void)
|
||||||
|
{
|
||||||
|
printf("%d\n", Parameter[0].Val.Integer);
|
||||||
|
}
|
||||||
|
|
||||||
void IntrinsicPrintf(void)
|
void IntrinsicPrintf(void)
|
||||||
{
|
{
|
||||||
printf("IntrinsicPrintf\n");
|
printf("IntrinsicPrintf\n");
|
||||||
|
@ -22,6 +27,7 @@ struct IntrinsicFunction
|
||||||
{
|
{
|
||||||
{ IntrinsicSayHello, "void sayhello()" }, /* -1 */
|
{ IntrinsicSayHello, "void sayhello()" }, /* -1 */
|
||||||
{ IntrinsicPrintf, "void printf()" }, /* -2 */
|
{ IntrinsicPrintf, "void printf()" }, /* -2 */
|
||||||
|
{ IntrinsicPrintInt, "void printint(int)" }, /* -3 */
|
||||||
};
|
};
|
||||||
|
|
||||||
void IntrinsicInit(struct Table *GlobalTable)
|
void IntrinsicInit(struct Table *GlobalTable)
|
||||||
|
|
44
lex.c
44
lex.c
|
@ -4,13 +4,12 @@
|
||||||
#include "picoc.h"
|
#include "picoc.h"
|
||||||
|
|
||||||
|
|
||||||
#define isCidstart(c) (isalpha(c) || (c)=='_')
|
#define isCidstart(c) (isalpha(c) || (c)=='_' || (c)=='#')
|
||||||
#define isCident(c) (isalnum(c) || (c)=='_')
|
#define isCident(c) (isalnum(c) || (c)=='_')
|
||||||
|
|
||||||
#define LEXINC Lexer->Pos++
|
#define NEXTIS(c,x,y) { if (NextChar == (c)) { Lexer->Pos++; return (x); } else return (y); }
|
||||||
#define NEXTIS(c,x,y) { if (NextChar == (c)) { LEXINC; return (x); } else return (y); }
|
#define NEXTIS3(c,x,d,y,z) { if (NextChar == (c)) { Lexer->Pos++; return (x); } else NEXTIS(d,y,z) }
|
||||||
#define NEXTIS3(c,x,d,y,z) { if (NextChar == (c)) { LEXINC; return (x); } else NEXTIS(d,y,z) }
|
#define NEXTIS4(c,x,d,y,e,z,a) { if (NextChar == (c)) { Lexer->Pos++; return (x); } else NEXTIS3(d,y,e,z,a) }
|
||||||
#define NEXTIS4(c,x,d,y,e,z,a) { if (NextChar == (c)) { LEXINC; return (x); } else NEXTIS3(d,y,e,z,a) }
|
|
||||||
|
|
||||||
|
|
||||||
struct ReservedWord
|
struct ReservedWord
|
||||||
|
@ -21,6 +20,8 @@ struct ReservedWord
|
||||||
|
|
||||||
static struct ReservedWord ReservedWords[] =
|
static struct ReservedWord ReservedWords[] =
|
||||||
{
|
{
|
||||||
|
{ "#define", TokenHashDefine },
|
||||||
|
{ "#include", TokenHashInclude },
|
||||||
{ "break", TokenBreak },
|
{ "break", TokenBreak },
|
||||||
{ "case", TokenCase },
|
{ "case", TokenCase },
|
||||||
{ "char", TokenCharType },
|
{ "char", TokenCharType },
|
||||||
|
@ -138,6 +139,26 @@ enum LexToken LexGetCharacterConstant(struct LexState *Lexer, union AnyValue *Va
|
||||||
return TokenCharacterConstant;
|
return TokenCharacterConstant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum LexToken LexGetComment(struct LexState *Lexer, char NextChar, union AnyValue *Value)
|
||||||
|
{
|
||||||
|
Lexer->Pos++;
|
||||||
|
if (NextChar == '*')
|
||||||
|
{ /* conventional C comment */
|
||||||
|
while (Lexer->Pos != Lexer->End && (*(Lexer->Pos-1) != '*' || *Lexer->Pos != '/'))
|
||||||
|
Lexer->Pos++;
|
||||||
|
|
||||||
|
if (Lexer->Pos != Lexer->End)
|
||||||
|
Lexer->Pos++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ /* C++ style comment */
|
||||||
|
while (Lexer->Pos != Lexer->End && *Lexer->Pos != '\n')
|
||||||
|
Lexer->Pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LexGetToken(Lexer, Value);
|
||||||
|
}
|
||||||
|
|
||||||
enum LexToken LexGetToken(struct LexState *Lexer, union AnyValue *Value)
|
enum LexToken LexGetToken(struct LexState *Lexer, union AnyValue *Value)
|
||||||
{
|
{
|
||||||
char ThisChar;
|
char ThisChar;
|
||||||
|
@ -147,7 +168,7 @@ enum LexToken LexGetToken(struct LexState *Lexer, union AnyValue *Value)
|
||||||
{
|
{
|
||||||
if (*Lexer->Pos == '\n')
|
if (*Lexer->Pos == '\n')
|
||||||
Lexer->Line++;
|
Lexer->Line++;
|
||||||
|
|
||||||
Lexer->Pos++;
|
Lexer->Pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +183,7 @@ enum LexToken LexGetToken(struct LexState *Lexer, union AnyValue *Value)
|
||||||
return LexGetNumber(Lexer, Value);
|
return LexGetNumber(Lexer, Value);
|
||||||
|
|
||||||
NextChar = (Lexer->Pos+1 != Lexer->End) ? *(Lexer->Pos+1) : 0;
|
NextChar = (Lexer->Pos+1 != Lexer->End) ? *(Lexer->Pos+1) : 0;
|
||||||
LEXINC;
|
Lexer->Pos++;
|
||||||
switch (ThisChar)
|
switch (ThisChar)
|
||||||
{
|
{
|
||||||
case '"': return LexGetStringConstant(Lexer, Value);
|
case '"': return LexGetStringConstant(Lexer, Value);
|
||||||
|
@ -173,7 +194,7 @@ enum LexToken LexGetToken(struct LexState *Lexer, union AnyValue *Value)
|
||||||
case '+': NEXTIS3('=', TokenAddAssign, '+', TokenIncrement, TokenPlus);
|
case '+': NEXTIS3('=', TokenAddAssign, '+', TokenIncrement, TokenPlus);
|
||||||
case '-': NEXTIS4('=', TokenSubtractAssign, '>', TokenArrow, '-', TokenDecrement, TokenMinus);
|
case '-': NEXTIS4('=', TokenSubtractAssign, '>', TokenArrow, '-', TokenDecrement, TokenMinus);
|
||||||
case '*': return TokenAsterisk;
|
case '*': return TokenAsterisk;
|
||||||
case '/': return TokenSlash;
|
case '/': if (NextChar == '/' || NextChar == '*') return LexGetComment(Lexer, NextChar, Value); else return TokenSlash;
|
||||||
case '<': NEXTIS('=', TokenLessEqual, TokenLessThan);
|
case '<': NEXTIS('=', TokenLessEqual, TokenLessThan);
|
||||||
case '>': NEXTIS('=', TokenGreaterEqual, TokenGreaterThan);
|
case '>': NEXTIS('=', TokenGreaterEqual, TokenGreaterThan);
|
||||||
case ';': return TokenSemicolon;
|
case ';': return TokenSemicolon;
|
||||||
|
@ -214,3 +235,10 @@ enum LexToken LexPeekPlainToken(struct LexState *Lexer)
|
||||||
return LexGetToken(&LocalState, &Value);
|
return LexGetToken(&LocalState, &Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* skip everything up to the end of the line */
|
||||||
|
void LexToEndOfLine(struct LexState *Lexer)
|
||||||
|
{
|
||||||
|
while (Lexer->Pos != Lexer->End && *Lexer->Pos != '\n')
|
||||||
|
Lexer->Pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
140
parse.c
140
parse.c
|
@ -149,7 +149,9 @@ void ParseFunctionCall(struct LexState *Lexer, struct Value *Result, Str *FuncNa
|
||||||
VariableGet(Lexer, FuncName, Result, &LValue);
|
VariableGet(Lexer, FuncName, Result, &LValue);
|
||||||
if (Result->Typ != TypeFunction)
|
if (Result->Typ != TypeFunction)
|
||||||
ProgramFail(Lexer, "not a function - can't call");
|
ProgramFail(Lexer, "not a function - can't call");
|
||||||
|
|
||||||
|
// XXX - handle macros here too
|
||||||
|
|
||||||
StackFrameAdd(Lexer);
|
StackFrameAdd(Lexer);
|
||||||
if (Result->Val.Integer >= 0)
|
if (Result->Val.Integer >= 0)
|
||||||
FuncLexer = FunctionStore[Result->Val.Integer];
|
FuncLexer = FunctionStore[Result->Val.Integer];
|
||||||
|
@ -219,7 +221,11 @@ int ParseValue(struct LexState *Lexer, struct Value *Result, struct Value **LVal
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (RunIt)
|
if (RunIt)
|
||||||
|
{
|
||||||
VariableGet(Lexer, &Result->Val.String, Result, LValue);
|
VariableGet(Lexer, &Result->Val.String, Result, LValue);
|
||||||
|
if (!ISVALUETYPE(Result->Typ))
|
||||||
|
ProgramFail(Lexer, "bad variable type");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -382,10 +388,60 @@ void ParseFunctionDefinition(struct LexState *Lexer, Str *Identifier, struct Lex
|
||||||
ProgramFail(Lexer, "'%S' is already defined", Identifier);
|
ProgramFail(Lexer, "'%S' is already defined", Identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ParseFor(struct LexState *Lexer, struct Value *Result, int RunIt)
|
||||||
|
{
|
||||||
|
struct Value Conditional;
|
||||||
|
struct LexState PreConditional;
|
||||||
|
struct LexState PreIncrement;
|
||||||
|
struct LexState PreStatement;
|
||||||
|
struct LexState After;
|
||||||
|
|
||||||
|
if (LexGetPlainToken(Lexer) != TokenOpenBracket)
|
||||||
|
ProgramFail(Lexer, "'(' expected");
|
||||||
|
|
||||||
|
if (!ParseStatement(Lexer, RunIt))
|
||||||
|
ProgramFail(Lexer, "statement expected");
|
||||||
|
|
||||||
|
PreConditional = *Lexer;
|
||||||
|
ParseIntExpression(Lexer, &Conditional, RunIt);
|
||||||
|
|
||||||
|
if (LexGetPlainToken(Lexer) != TokenSemicolon)
|
||||||
|
ProgramFail(Lexer, "';' expected");
|
||||||
|
|
||||||
|
PreIncrement = *Lexer;
|
||||||
|
ParseStatement(Lexer, FALSE);
|
||||||
|
|
||||||
|
if (LexGetPlainToken(Lexer) != TokenCloseBracket)
|
||||||
|
ProgramFail(Lexer, "')' expected");
|
||||||
|
|
||||||
|
PreStatement = *Lexer;
|
||||||
|
if (!ParseStatement(Lexer, RunIt && Conditional.Val.Integer))
|
||||||
|
ProgramFail(Lexer, "statement expected");
|
||||||
|
|
||||||
|
After = *Lexer;
|
||||||
|
|
||||||
|
while (Conditional.Val.Integer && RunIt)
|
||||||
|
{
|
||||||
|
*Lexer = PreIncrement;
|
||||||
|
ParseStatement(Lexer, TRUE);
|
||||||
|
|
||||||
|
*Lexer = PreConditional;
|
||||||
|
ParseIntExpression(Lexer, &Conditional, RunIt);
|
||||||
|
|
||||||
|
if (Conditional.Val.Integer)
|
||||||
|
{
|
||||||
|
*Lexer = PreStatement;
|
||||||
|
ParseStatement(Lexer, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*Lexer = After;
|
||||||
|
}
|
||||||
|
|
||||||
/* parse a statement */
|
/* parse a statement */
|
||||||
int ParseStatement(struct LexState *Lexer, int RunIt)
|
int ParseStatement(struct LexState *Lexer, int RunIt)
|
||||||
{
|
{
|
||||||
struct Value Conditional;
|
struct Value CValue;
|
||||||
struct LexState PreState = *Lexer;
|
struct LexState PreState = *Lexer;
|
||||||
union AnyValue LexerValue;
|
union AnyValue LexerValue;
|
||||||
enum ValueType Typ;
|
enum ValueType Typ;
|
||||||
|
@ -398,7 +454,7 @@ int ParseStatement(struct LexState *Lexer, int RunIt)
|
||||||
|
|
||||||
case TokenIdentifier:
|
case TokenIdentifier:
|
||||||
*Lexer = PreState;
|
*Lexer = PreState;
|
||||||
ParseExpression(Lexer, &Conditional, RunIt);
|
ParseExpression(Lexer, &CValue, RunIt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TokenLeftBrace:
|
case TokenLeftBrace:
|
||||||
|
@ -410,15 +466,15 @@ int ParseStatement(struct LexState *Lexer, int RunIt)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TokenIf:
|
case TokenIf:
|
||||||
ParseIntExpression(Lexer, &Conditional, RunIt);
|
ParseIntExpression(Lexer, &CValue, RunIt);
|
||||||
|
|
||||||
if (!ParseStatement(Lexer, RunIt && Conditional.Val.Integer))
|
if (!ParseStatement(Lexer, RunIt && CValue.Val.Integer))
|
||||||
ProgramFail(Lexer, "statement expected");
|
ProgramFail(Lexer, "statement expected");
|
||||||
|
|
||||||
if (LexPeekToken(Lexer, &LexerValue) == TokenElse)
|
if (LexPeekToken(Lexer, &LexerValue) == TokenElse)
|
||||||
{
|
{
|
||||||
LexGetToken(Lexer, &LexerValue);
|
LexGetToken(Lexer, &LexerValue);
|
||||||
if (!ParseStatement(Lexer, RunIt && !Conditional.Val.Integer))
|
if (!ParseStatement(Lexer, RunIt && !CValue.Val.Integer))
|
||||||
ProgramFail(Lexer, "statement expected");
|
ProgramFail(Lexer, "statement expected");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -429,12 +485,12 @@ int ParseStatement(struct LexState *Lexer, int RunIt)
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
*Lexer = PreConditional;
|
*Lexer = PreConditional;
|
||||||
ParseIntExpression(Lexer, &Conditional, RunIt);
|
ParseIntExpression(Lexer, &CValue, RunIt);
|
||||||
|
|
||||||
if (!ParseStatement(Lexer, RunIt && Conditional.Val.Integer))
|
if (!ParseStatement(Lexer, RunIt && CValue.Val.Integer))
|
||||||
ProgramFail(Lexer, "statement expected");
|
ProgramFail(Lexer, "statement expected");
|
||||||
|
|
||||||
} while (RunIt && Conditional.Val.Integer);
|
} while (RunIt && CValue.Val.Integer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -447,60 +503,13 @@ int ParseStatement(struct LexState *Lexer, int RunIt)
|
||||||
if (!ParseStatement(Lexer, RunIt))
|
if (!ParseStatement(Lexer, RunIt))
|
||||||
ProgramFail(Lexer, "statement expected");
|
ProgramFail(Lexer, "statement expected");
|
||||||
|
|
||||||
ParseIntExpression(Lexer, &Conditional, RunIt);
|
ParseIntExpression(Lexer, &CValue, RunIt);
|
||||||
|
|
||||||
} while (Conditional.Val.Integer && RunIt);
|
} while (CValue.Val.Integer && RunIt);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TokenFor:
|
case TokenFor:
|
||||||
{
|
|
||||||
struct LexState PreConditional;
|
|
||||||
struct LexState PreIncrement;
|
|
||||||
struct LexState PreStatement;
|
|
||||||
struct LexState After;
|
|
||||||
|
|
||||||
if (LexGetToken(Lexer, &LexerValue) != TokenOpenBracket)
|
|
||||||
ProgramFail(Lexer, "'(' expected");
|
|
||||||
|
|
||||||
if (!ParseStatement(Lexer, RunIt))
|
|
||||||
ProgramFail(Lexer, "statement expected");
|
|
||||||
|
|
||||||
PreConditional = *Lexer;
|
|
||||||
ParseIntExpression(Lexer, &Conditional, RunIt);
|
|
||||||
|
|
||||||
if (LexGetToken(Lexer, &LexerValue) != TokenSemicolon)
|
|
||||||
ProgramFail(Lexer, "';' expected");
|
|
||||||
|
|
||||||
PreIncrement = *Lexer;
|
|
||||||
ParseStatement(Lexer, FALSE);
|
|
||||||
|
|
||||||
if (LexGetToken(Lexer, &LexerValue) != TokenCloseBracket)
|
|
||||||
ProgramFail(Lexer, "')' expected");
|
|
||||||
|
|
||||||
PreStatement = *Lexer;
|
|
||||||
if (!ParseStatement(Lexer, RunIt && Conditional.Val.Integer))
|
|
||||||
ProgramFail(Lexer, "statement expected");
|
|
||||||
|
|
||||||
After = *Lexer;
|
|
||||||
|
|
||||||
while (Conditional.Val.Integer && RunIt)
|
|
||||||
{
|
|
||||||
*Lexer = PreIncrement;
|
|
||||||
ParseStatement(Lexer, TRUE);
|
|
||||||
|
|
||||||
*Lexer = PreConditional;
|
|
||||||
ParseIntExpression(Lexer, &Conditional, RunIt);
|
|
||||||
|
|
||||||
if (Conditional.Val.Integer)
|
|
||||||
{
|
|
||||||
*Lexer = PreStatement;
|
|
||||||
ParseStatement(Lexer, TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*Lexer = After;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TokenSemicolon: break;
|
case TokenSemicolon: break;
|
||||||
|
@ -531,6 +540,21 @@ int ParseStatement(struct LexState *Lexer, int RunIt)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TokenHashDefine:
|
||||||
|
if (LexGetToken(Lexer, &LexerValue) != TokenIdentifier)
|
||||||
|
ProgramFail(Lexer, "identifier expected");
|
||||||
|
|
||||||
|
CValue.Val.String.Str = Lexer->Pos;
|
||||||
|
LexToEndOfLine(Lexer);
|
||||||
|
CValue.Val.String.Len = Lexer->Pos - CValue.Val.String.Str;
|
||||||
|
CValue.Typ = TypeMacro;
|
||||||
|
VariableDefine(Lexer, &LexerValue.String, &CValue);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TokenHashInclude:
|
||||||
|
ProgramFail(Lexer, "not implemented");
|
||||||
|
break;
|
||||||
|
|
||||||
case TokenDefault:
|
case TokenDefault:
|
||||||
if (RunIt)
|
if (RunIt)
|
||||||
printf("Hello\n");
|
printf("Hello\n");
|
||||||
|
|
16
picoc.h
16
picoc.h
|
@ -32,6 +32,8 @@
|
||||||
#define PATH_MAX 1024
|
#define PATH_MAX 1024
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define ISVALUETYPE(t) (((t) == TypeInt) || ((t) == TypeFP) || ((t) == TypeString))
|
||||||
|
|
||||||
/* lexical tokens */
|
/* lexical tokens */
|
||||||
enum LexToken
|
enum LexToken
|
||||||
{
|
{
|
||||||
|
@ -88,7 +90,10 @@ enum LexToken
|
||||||
TokenSwitch,
|
TokenSwitch,
|
||||||
TokenCase,
|
TokenCase,
|
||||||
TokenDefault,
|
TokenDefault,
|
||||||
TokenReturn
|
TokenReturn,
|
||||||
|
TokenHashDefine,
|
||||||
|
TokenHashInclude,
|
||||||
|
TokenEndOfLine
|
||||||
};
|
};
|
||||||
|
|
||||||
/* string type so we can use source file strings */
|
/* string type so we can use source file strings */
|
||||||
|
@ -113,7 +118,8 @@ enum ValueType
|
||||||
TypeInt,
|
TypeInt,
|
||||||
TypeFP,
|
TypeFP,
|
||||||
TypeString,
|
TypeString,
|
||||||
TypeFunction
|
TypeFunction,
|
||||||
|
TypeMacro
|
||||||
};
|
};
|
||||||
|
|
||||||
union AnyValue
|
union AnyValue
|
||||||
|
@ -160,7 +166,10 @@ struct StackFrame
|
||||||
};
|
};
|
||||||
|
|
||||||
/* globals */
|
/* globals */
|
||||||
extern struct Table GlobalTable;
|
struct Table GlobalTable;
|
||||||
|
extern struct Value Parameter[PARAMETER_MAX];
|
||||||
|
extern int ParameterUsed;
|
||||||
|
extern struct Value ReturnValue;
|
||||||
|
|
||||||
/* str.c */
|
/* str.c */
|
||||||
void StrToC(char *Dest, int DestSize, const Str *Source);
|
void StrToC(char *Dest, int DestSize, const Str *Source);
|
||||||
|
@ -186,6 +195,7 @@ enum LexToken LexGetToken(struct LexState *Lexer, union AnyValue *Value);
|
||||||
enum LexToken LexGetPlainToken(struct LexState *Lexer);
|
enum LexToken LexGetPlainToken(struct LexState *Lexer);
|
||||||
enum LexToken LexPeekToken(struct LexState *Lexer, union AnyValue *Value);
|
enum LexToken LexPeekToken(struct LexState *Lexer, union AnyValue *Value);
|
||||||
enum LexToken LexPeekPlainToken(struct LexState *Lexer);
|
enum LexToken LexPeekPlainToken(struct LexState *Lexer);
|
||||||
|
void LexToEndOfLine(struct LexState *Lexer);
|
||||||
|
|
||||||
/* parse.c */
|
/* parse.c */
|
||||||
void ParseInit(void);
|
void ParseInit(void);
|
||||||
|
|
11
test/Makefile
Normal file
11
test/Makefile
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
TESTS= assignment.test \
|
||||||
|
comment.test \
|
||||||
|
printf.test
|
||||||
|
|
||||||
|
%.test: %.t
|
||||||
|
@./picotest.sh $<
|
||||||
|
|
||||||
|
all: test
|
||||||
|
|
||||||
|
test: $(TESTS)
|
||||||
|
@echo "test passed"
|
5
test/assignment.t
Normal file
5
test/assignment.t
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
int a;
|
||||||
|
a = 42;
|
||||||
|
printint(a);
|
||||||
|
%%
|
||||||
|
42
|
25
test/picotest.sh
Executable file
25
test/picotest.sh
Executable file
|
@ -0,0 +1,25 @@
|
||||||
|
#!/bin/sh
|
||||||
|
if [ ! -f $1 ]
|
||||||
|
then
|
||||||
|
echo "no test file $1"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TESTNAME="`echo $1 | sed 's/\.t$//'`"
|
||||||
|
echo $TESTNAME...
|
||||||
|
|
||||||
|
awk '{ if ($1 == "%%") hide = 1; if (hide != 1) print; }' <$TESTNAME.t >$TESTNAME.c
|
||||||
|
awk '{ if (show == 1) print; if ($1 == "%%") show = 1; }' <$TESTNAME.t >$TESTNAME.expect
|
||||||
|
|
||||||
|
../picoc $TESTNAME.c 2>&1 >$TESTNAME.out
|
||||||
|
|
||||||
|
if [ "x`diff -q $TESTNAME.expect $TESTNAME.out`" != "x" ]
|
||||||
|
then
|
||||||
|
echo "error in test $TESTNAME"
|
||||||
|
diff -u $TESTNAME.expect $TESTNAME.out
|
||||||
|
rm -f $TESTNAME.c $TESTNAME.expect $TESTNAME.out
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f $TESTNAME.c $TESTNAME.expect $TESTNAME.out
|
||||||
|
|
3
test/printf.t
Normal file
3
test/printf.t
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
default
|
||||||
|
%%
|
||||||
|
Hello
|
Loading…
Reference in a new issue