Start sketching out single-pass compiler.

This commit is contained in:
Bob Nystrom
2013-10-22 12:16:39 -07:00
parent d26c38abb1
commit dd8998db24
10 changed files with 512 additions and 457 deletions

View File

@ -1 +1 @@
123(1, true, "a string".whatevs)
2

373
src/compiler.c Normal file
View File

@ -0,0 +1,373 @@
#include <stdio.h>
#include <stdarg.h>
#include "compiler.h"
typedef struct
{
Buffer* source;
Token* current;
// The block being compiled.
Block* block;
int numCodes;
// Non-zero if a compile error has occurred.
int hasError;
} Compiler;
typedef void (*CompileFn)(Compiler*, Token*);
typedef struct
{
CompileFn fn;
int precedence;
} InfixCompiler;
/*
static void block(Compiler* compiler);
*/
static void statementLike(Compiler* compiler);
static void expression(Compiler* compiler);
static void compilePrecedence(Compiler* compiler, int precedence);
static void prefixLiteral(Compiler* compiler, Token* token);
static void infixCall(Compiler* compiler, Token* token);
static void infixBinaryOp(Compiler* compiler, Token* token);
static TokenType peek(Compiler* compiler);
static Token* match(Compiler* compiler, TokenType expected);
static Token* consume(Compiler* compiler, TokenType expected);
static Token* advance(Compiler* compiler);
static void error(Compiler* compiler, const char* format, ...);
enum
{
PREC_NONE,
PREC_LOWEST,
PREC_EQUALITY, // == !=
PREC_COMPARISON, // < > <= >=
PREC_BITWISE, // | &
PREC_TERM, // + -
PREC_FACTOR, // * / %
PREC_CALL // ()
};
CompileFn prefixCompilers[] = {
NULL, // TOKEN_LEFT_PAREN
NULL, // TOKEN_RIGHT_PAREN
NULL, // TOKEN_LEFT_BRACKET
NULL, // TOKEN_RIGHT_BRACKET
NULL, // TOKEN_LEFT_BRACE
NULL, // TOKEN_RIGHT_BRACE
NULL, // TOKEN_COLON
NULL, // TOKEN_DOT
NULL, // TOKEN_COMMA
NULL, // TOKEN_STAR
NULL, // TOKEN_SLASH
NULL, // TOKEN_PERCENT
NULL, // TOKEN_PLUS
NULL, // TOKEN_MINUS
NULL, // TOKEN_PIPE
NULL, // TOKEN_AMP
NULL, // TOKEN_BANG
NULL, // TOKEN_EQ
NULL, // TOKEN_LT
NULL, // TOKEN_GT
NULL, // TOKEN_LTEQ
NULL, // TOKEN_GTEQ
NULL, // TOKEN_EQEQ
NULL, // TOKEN_BANGEQ
NULL, // TOKEN_ELSE
NULL, // TOKEN_IF
NULL, // TOKEN_VAR
NULL, // TOKEN_EMBEDDED
prefixLiteral, // TOKEN_NAME
prefixLiteral, // TOKEN_NUMBER
prefixLiteral, // TOKEN_STRING
NULL, // TOKEN_LINE
NULL, // TOKEN_WHITESPACE
NULL, // TOKEN_INDENT
NULL, // TOKEN_OUTDENT
NULL, // TOKEN_ERROR
NULL // TOKEN_EOF
};
// The indices in this array correspond to TOKEN enum values.
InfixCompiler infixCompilers[] = {
{ infixCall, PREC_CALL }, // TOKEN_LEFT_PAREN
{ NULL, PREC_NONE }, // TOKEN_RIGHT_PAREN
{ NULL, PREC_NONE }, // TOKEN_LEFT_BRACKET
{ NULL, PREC_NONE }, // TOKEN_RIGHT_BRACKET
{ NULL, PREC_NONE }, // TOKEN_LEFT_BRACE
{ NULL, PREC_NONE }, // TOKEN_RIGHT_BRACE
{ NULL, PREC_NONE }, // TOKEN_COLON
{ NULL, PREC_NONE }, // TOKEN_DOT
{ NULL, PREC_NONE }, // TOKEN_COMMA
{ infixBinaryOp, PREC_FACTOR }, // TOKEN_STAR
{ infixBinaryOp, PREC_FACTOR }, // TOKEN_SLASH
{ infixBinaryOp, PREC_FACTOR }, // TOKEN_PERCENT
{ infixBinaryOp, PREC_TERM }, // TOKEN_PLUS
{ infixBinaryOp, PREC_TERM }, // TOKEN_MINUS
{ infixBinaryOp, PREC_BITWISE }, // TOKEN_PIPE
{ infixBinaryOp, PREC_BITWISE }, // TOKEN_AMP
{ NULL, PREC_NONE }, // TOKEN_BANG
{ NULL, PREC_NONE }, // TOKEN_EQ
{ infixBinaryOp, PREC_COMPARISON }, // TOKEN_LT
{ infixBinaryOp, PREC_COMPARISON }, // TOKEN_GT
{ infixBinaryOp, PREC_COMPARISON }, // TOKEN_LTEQ
{ infixBinaryOp, PREC_COMPARISON }, // TOKEN_GTEQ
{ infixBinaryOp, PREC_EQUALITY }, // TOKEN_EQEQ
{ infixBinaryOp, PREC_EQUALITY }, // TOKEN_BANGEQ
{ NULL, PREC_NONE }, // TOKEN_ELSE
{ NULL, PREC_NONE }, // TOKEN_IF
{ NULL, PREC_NONE }, // TOKEN_VAR
{ NULL, PREC_NONE }, // TOKEN_EMBEDDED
{ NULL, PREC_NONE }, // TOKEN_NAME
{ NULL, PREC_NONE }, // TOKEN_NUMBER
{ NULL, PREC_NONE }, // TOKEN_STRING
{ NULL, PREC_NONE }, // TOKEN_LINE
{ NULL, PREC_NONE }, // TOKEN_WHITESPACE
{ NULL, PREC_NONE }, // TOKEN_INDENT
{ NULL, PREC_NONE }, // TOKEN_OUTDENT
{ NULL, PREC_NONE }, // TOKEN_ERROR
{ NULL, PREC_NONE } // TOKEN_EOF
};
Block* compile(Buffer* source, Token* tokens)
{
Compiler compiler;
compiler.source = source;
compiler.current = tokens;
compiler.hasError = 0;
compiler.block = malloc(sizeof(Block));
// TODO(bob): Hack! make variable sized.
compiler.block->bytecode = malloc(sizeof(Code) * 1024);
// TODO(bob): Hack! make variable sized.
compiler.block->constants = malloc(sizeof(Value) * 256);
compiler.block->numConstants = 0;
compiler.numCodes = 0;
// TODO(bob): Copied from block(). Unify.
do
{
statementLike(&compiler);
} while (!match(&compiler, TOKEN_EOF));
compiler.block->bytecode[compiler.numCodes++] = CODE_END;
return compiler.hasError ? NULL : compiler.block;
}
/*
static void block(Compiler* compiler)
{
consume(compiler, TOKEN_INDENT);
NodeSequence* sequence = malloc(sizeof(NodeSequence));
sequence->node.type = NODE_SEQUENCE;
sequence->nodes = NULL;
NodeList** nodes = &sequence->nodes;
do
{
Node* node = statementLike(compiler);
*nodes = malloc(sizeof(NodeList));
(*nodes)->node = node;
(*nodes)->next = NULL;
nodes = &(*nodes)->next;
} while (!match(compiler, TOKEN_OUTDENT));
return (Node*)sequence;
}
*/
static void statementLike(Compiler* compiler)
{
/*
if (match(compiler, TOKEN_IF))
{
// Compile the condition.
expression(compiler);
consume(compiler, TOKEN_COLON);
// Compile the then arm.
block(compiler);
// Compile the else arm.
if (match(compiler, TOKEN_ELSE))
{
consume(compiler, TOKEN_COLON);
block(parser);
}
return;
}
if (match(compiler, TOKEN_VAR))
{
Token* name = consume(compiler, TOKEN_NAME);
Node* initializer = NULL;
if (match(compiler, TOKEN_EQ))
{
initializer = expression(parser);
}
if (peek(parser) != TOKEN_OUTDENT) consume(compiler, TOKEN_LINE);
NodeVar* node = malloc(sizeof(NodeVar));
node->node.type = NODE_VAR;
node->name = name;
node->initializer = initializer;
return (Node*)node;
}
*/
// Statement expression.
expression(compiler);
consume(compiler, TOKEN_LINE);
}
static void expression(Compiler* compiler)
{
compilePrecedence(compiler, PREC_LOWEST);
}
void compilePrecedence(Compiler* compiler, int precedence)
{
Token* token = advance(compiler);
CompileFn prefix = prefixCompilers[token->type];
if (prefix == NULL)
{
// TODO(bob): Handle error better.
error(compiler, "No prefix parser.");
exit(1);
}
prefix(compiler, token);
while (precedence <= infixCompilers[compiler->current->type].precedence)
{
token = advance(compiler);
CompileFn infix = infixCompilers[token->type].fn;
infix(compiler, token);
}
}
static void prefixLiteral(Compiler* compiler, Token* token)
{
// TODO(bob): Get actual value from token!
// Define a constant for the literal.
// TODO(bob): See if constant with same value already exists.
Value constant = malloc(sizeof(Obj));
constant->type = OBJ_INT;
constant->flags = 0;
constant->value = 234;
compiler->block->constants[compiler->block->numConstants++] = constant;
// Compile the code to load the constant.
compiler->block->bytecode[compiler->numCodes++] = CODE_CONSTANT;
compiler->block->bytecode[compiler->numCodes++] = compiler->block->numConstants - 1;
}
static void infixCall(Compiler* compiler, Token* token)
{
printf("infix calls not implemented\n");
exit(1);
/*
NodeList* args = NULL;
if (match(compiler, TOKEN_RIGHT_PAREN) == NULL)
{
NodeList** arg = &args;
do
{
*arg = malloc(sizeof(NodeList));
(*arg)->node = expression(parser);
(*arg)->next = NULL;
arg = &(*arg)->next;
}
while (match(compiler, TOKEN_COMMA) != NULL);
consume(compiler, TOKEN_RIGHT_PAREN);
}
NodeCall* node = malloc(sizeof(NodeCall));
node->node.type = NODE_CALL;
node->fn = left;
node->args = args;
return (Node*)node;
*/
}
static void infixBinaryOp(Compiler* compiler, Token* token)
{
printf("infix binary ops not implemented\n");
exit(1);
/*
// TODO(bob): Support right-associative infix. Needs to do precedence
// - 1 here to be right-assoc.
Node* right = parsePrecedence(parser,
infixParsers[token->type].precedence);
NodeBinaryOp* node = malloc(sizeof(NodeBinaryOp));
node->node.type = NODE_BINARY_OP;
node->left = left;
node->op = token;
node->right = right;
return (Node*)node;
*/
}
static TokenType peek(Compiler* compiler)
{
return compiler->current->type;
}
static Token* match(Compiler* compiler, TokenType expected)
{
if (peek(compiler) != expected) return NULL;
return advance(compiler);
}
static Token* consume(Compiler* compiler, TokenType expected)
{
Token* token = advance(compiler);
if (token->type != expected)
{
// TODO(bob): Better error.
error(compiler, "Expected %d, got %d.\n", expected, token->type);
}
return token;
}
static Token* advance(Compiler* compiler)
{
// TODO(bob): Check for EOF.
Token* token = compiler->current;
compiler->current = compiler->current->next;
return unlinkToken(token);
}
static void error(Compiler* compiler, const char* format, ...)
{
compiler->hasError = 1;
printf("Compile error on '");
printToken(compiler->source, compiler->current);
printf("': ");
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
printf("\n");
}

9
src/compiler.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef wren_parser_h
#define wren_parser_h
#include "lexer.h"
#include "vm.h"
Block* compile(Buffer* source, Token* tokens);
#endif

View File

@ -1,8 +1,9 @@
#include <stdio.h>
#include <stdlib.h>
#include "compiler.h"
#include "lexer.h"
#include "parser.h"
#include "vm.h"
#define MAX_FILE_SIZE 256 * 256
@ -32,14 +33,13 @@ int main(int argc, const char * argv[])
//printf("Cleaned tokens:\n");
dumpTokens(buffer, tokens);
/*Node* node =*/ parse(buffer, tokens);
/*
if (defns) generate(buffer, defns);
Block* block = compile(buffer, tokens);
Fiber* fiber = newFiber();
Value value = interpret(fiber, block);
printValue(value);
// TODO(bob): Free tokens.
// TODO(bob): Free ast.
*/
freeBuffer(buffer);
@ -52,8 +52,6 @@ static void dumpTokens(Buffer* buffer, Token* token)
{
switch (token->type)
{
case TOKEN_INDENT: printf("(in)"); break;
case TOKEN_OUTDENT: printf("(out)"); break;
case TOKEN_LINE: printf("(line)"); break;
case TOKEN_ERROR: printf("(error)"); break;
case TOKEN_EOF: printf("(eof)"); break;

View File

@ -1,349 +0,0 @@
#include <stdio.h>
#include <stdarg.h>
#include "parser.h"
typedef struct
{
Buffer* source;
Token* current;
// Non-zero if a parse error has occurred.
int hasError;
} Parser;
typedef Node* (*PrefixParserFn)(Parser*, Token*);
typedef Node* (*InfixParserFn)(Parser*, Node*, Token*);
typedef struct
{
InfixParserFn fn;
int precedence;
} InfixParser;
static Node* block(Parser* parser);
static Node* statementLike(Parser* parser);
static Node* expression(Parser* parser);
static Node* parsePrecedence(Parser* parser, int precedence);
static Node* prefixLiteral(Parser* parser, Token* token);
static Node* infixCall(Parser* parser, Node* left, Token* token);
static Node* infixBinaryOp(Parser* parser, Node* left, Token* token);
static TokenType peek(Parser* parser);
static Token* match(Parser* parser, TokenType expected);
static Token* consume(Parser* parser, TokenType expected);
static Token* advance(Parser* parser);
static void error(Parser* parser, const char* format, ...);
enum
{
PREC_NONE,
PREC_LOWEST,
PREC_EQUALITY, // == !=
PREC_COMPARISON, // < > <= >=
PREC_BITWISE, // | &
PREC_TERM, // + -
PREC_FACTOR, // * / %
PREC_CALL // ()
};
PrefixParserFn prefixParsers[] = {
NULL, // TOKEN_LEFT_PAREN
NULL, // TOKEN_RIGHT_PAREN
NULL, // TOKEN_LEFT_BRACKET
NULL, // TOKEN_RIGHT_BRACKET
NULL, // TOKEN_LEFT_BRACE
NULL, // TOKEN_RIGHT_BRACE
NULL, // TOKEN_COLON
NULL, // TOKEN_DOT
NULL, // TOKEN_COMMA
NULL, // TOKEN_STAR
NULL, // TOKEN_SLASH
NULL, // TOKEN_PERCENT
NULL, // TOKEN_PLUS
NULL, // TOKEN_MINUS
NULL, // TOKEN_PIPE
NULL, // TOKEN_AMP
NULL, // TOKEN_BANG
NULL, // TOKEN_EQ
NULL, // TOKEN_LT
NULL, // TOKEN_GT
NULL, // TOKEN_LTEQ
NULL, // TOKEN_GTEQ
NULL, // TOKEN_EQEQ
NULL, // TOKEN_BANGEQ
NULL, // TOKEN_ELSE
NULL, // TOKEN_IF
NULL, // TOKEN_VAR
NULL, // TOKEN_EMBEDDED
prefixLiteral, // TOKEN_NAME
prefixLiteral, // TOKEN_NUMBER
prefixLiteral, // TOKEN_STRING
NULL, // TOKEN_LINE
NULL, // TOKEN_WHITESPACE
NULL, // TOKEN_INDENT
NULL, // TOKEN_OUTDENT
NULL, // TOKEN_ERROR
NULL // TOKEN_EOF
};
// The indices in this array correspond to TOKEN enum values.
InfixParser infixParsers[] = {
{ infixCall, PREC_CALL }, // TOKEN_LEFT_PAREN
{ NULL, PREC_NONE }, // TOKEN_RIGHT_PAREN
{ NULL, PREC_NONE }, // TOKEN_LEFT_BRACKET
{ NULL, PREC_NONE }, // TOKEN_RIGHT_BRACKET
{ NULL, PREC_NONE }, // TOKEN_LEFT_BRACE
{ NULL, PREC_NONE }, // TOKEN_RIGHT_BRACE
{ NULL, PREC_NONE }, // TOKEN_COLON
{ NULL, PREC_NONE }, // TOKEN_DOT
{ NULL, PREC_NONE }, // TOKEN_COMMA
{ infixBinaryOp, PREC_FACTOR }, // TOKEN_STAR
{ infixBinaryOp, PREC_FACTOR }, // TOKEN_SLASH
{ infixBinaryOp, PREC_FACTOR }, // TOKEN_PERCENT
{ infixBinaryOp, PREC_TERM }, // TOKEN_PLUS
{ infixBinaryOp, PREC_TERM }, // TOKEN_MINUS
{ infixBinaryOp, PREC_BITWISE }, // TOKEN_PIPE
{ infixBinaryOp, PREC_BITWISE }, // TOKEN_AMP
{ NULL, PREC_NONE }, // TOKEN_BANG
{ NULL, PREC_NONE }, // TOKEN_EQ
{ infixBinaryOp, PREC_COMPARISON }, // TOKEN_LT
{ infixBinaryOp, PREC_COMPARISON }, // TOKEN_GT
{ infixBinaryOp, PREC_COMPARISON }, // TOKEN_LTEQ
{ infixBinaryOp, PREC_COMPARISON }, // TOKEN_GTEQ
{ infixBinaryOp, PREC_EQUALITY }, // TOKEN_EQEQ
{ infixBinaryOp, PREC_EQUALITY }, // TOKEN_BANGEQ
{ NULL, PREC_NONE }, // TOKEN_ELSE
{ NULL, PREC_NONE }, // TOKEN_IF
{ NULL, PREC_NONE }, // TOKEN_VAR
{ NULL, PREC_NONE }, // TOKEN_EMBEDDED
{ NULL, PREC_NONE }, // TOKEN_NAME
{ NULL, PREC_NONE }, // TOKEN_NUMBER
{ NULL, PREC_NONE }, // TOKEN_STRING
{ NULL, PREC_NONE }, // TOKEN_LINE
{ NULL, PREC_NONE }, // TOKEN_WHITESPACE
{ NULL, PREC_NONE }, // TOKEN_INDENT
{ NULL, PREC_NONE }, // TOKEN_OUTDENT
{ NULL, PREC_NONE }, // TOKEN_ERROR
{ NULL, PREC_NONE } // TOKEN_EOF
};
Node* parse(Buffer* source, Token* tokens)
{
Parser parser;
parser.source = source;
parser.current = tokens;
parser.hasError = 0;
NodeSequence* sequence = (NodeSequence*)malloc(sizeof(NodeSequence));
sequence->node.type = NODE_SEQUENCE;
sequence->nodes = NULL;
// TODO(bob): Copied from block(). Unify.
NodeList** nodes = &sequence->nodes;
do
{
Node* node = statementLike(&parser);
*nodes = (NodeList*)malloc(sizeof(NodeList));
(*nodes)->node = node;
(*nodes)->next = NULL;
nodes = &(*nodes)->next;
} while (!match(&parser, TOKEN_EOF));
return parser.hasError ? NULL : (Node*)sequence;
}
static Node* block(Parser* parser)
{
consume(parser, TOKEN_INDENT);
NodeSequence* sequence = (NodeSequence*)malloc(sizeof(NodeSequence));
sequence->node.type = NODE_SEQUENCE;
sequence->nodes = NULL;
NodeList** nodes = &sequence->nodes;
do
{
Node* node = statementLike(parser);
*nodes = (NodeList*)malloc(sizeof(NodeList));
(*nodes)->node = node;
(*nodes)->next = NULL;
nodes = &(*nodes)->next;
} while (!match(parser, TOKEN_OUTDENT));
return (Node*)sequence;
}
static Node* statementLike(Parser* parser)
{
if (match(parser, TOKEN_IF))
{
Node* condition = expression(parser);
consume(parser, TOKEN_COLON);
Node* thenArm = block(parser);
Node* elseArm = NULL;
if (match(parser, TOKEN_ELSE))
{
consume(parser, TOKEN_COLON);
elseArm = block(parser);
}
NodeIf* expr = (NodeIf*)malloc(sizeof(NodeIf));
expr->node.type = NODE_IF;
expr->condition = condition;
expr->thenArm = thenArm;
expr->elseArm = elseArm;
return (Node*)expr;
}
if (match(parser, TOKEN_VAR))
{
Token* name = consume(parser, TOKEN_NAME);
Node* initializer = NULL;
if (match(parser, TOKEN_EQ))
{
initializer = expression(parser);
}
if (peek(parser) != TOKEN_OUTDENT) consume(parser, TOKEN_LINE);
NodeVar* node = (NodeVar*)malloc(sizeof(NodeVar));
node->node.type = NODE_VAR;
node->name = name;
node->initializer = initializer;
return (Node*)node;
}
// Statement expression.
Node* node = expression(parser);
if (peek(parser) != TOKEN_OUTDENT) consume(parser, TOKEN_LINE);
return node;
}
static Node* expression(Parser* parser)
{
return parsePrecedence(parser, PREC_LOWEST);
}
Node* parsePrecedence(Parser* parser, int precedence)
{
Token* token = advance(parser);
PrefixParserFn prefix = prefixParsers[token->type];
if (prefix == NULL)
{
// TODO(bob): Handle error better.
error(parser, "No prefix parser.");
exit(1);
}
Node* left = prefix(parser, token);
while (precedence <= infixParsers[parser->current->type].precedence)
{
token = advance(parser);
InfixParserFn infix = infixParsers[token->type].fn;
left = infix(parser, left, token);
}
return left;
}
static Node* prefixLiteral(Parser* parser, Token* token)
{
NodeLiteral* node = (NodeLiteral*)malloc(sizeof(NodeLiteral));
node->node.type = NODE_LITERAL;
node->token = token;
return (Node*)node;
}
static Node* infixCall(Parser* parser, Node* left, Token* token)
{
NodeList* args = NULL;
if (match(parser, TOKEN_RIGHT_PAREN) == NULL)
{
NodeList** arg = &args;
do
{
*arg = (NodeList*)malloc(sizeof(NodeList));
(*arg)->node = expression(parser);
(*arg)->next = NULL;
arg = &(*arg)->next;
}
while (match(parser, TOKEN_COMMA) != NULL);
consume(parser, TOKEN_RIGHT_PAREN);
}
NodeCall* node = (NodeCall*)malloc(sizeof(NodeCall));
node->node.type = NODE_CALL;
node->fn = left;
node->args = args;
return (Node*)node;
}
static Node* infixBinaryOp(Parser* parser, Node* left, Token* token)
{
// TODO(bob): Support right-associative infix. Needs to do precedence
// - 1 here to be right-assoc.
Node* right = parsePrecedence(parser,
infixParsers[token->type].precedence);
NodeBinaryOp* node = (NodeBinaryOp*)malloc(sizeof(NodeBinaryOp));
node->node.type = NODE_BINARY_OP;
node->left = left;
node->op = token;
node->right = right;
return (Node*)node;
}
static TokenType peek(Parser* parser)
{
return parser->current->type;
}
static Token* match(Parser* parser, TokenType expected)
{
if (peek(parser) != expected) return NULL;
return advance(parser);
}
static Token* consume(Parser* parser, TokenType expected)
{
Token* token = advance(parser);
if (token->type != expected)
{
// TODO(bob): Better error.
error(parser, "Expected %d, got %d.\n", expected, token->type);
}
return token;
}
static Token* advance(Parser* parser)
{
// TODO(bob): Check for EOF.
Token* token = parser->current;
parser->current = parser->current->next;
return unlinkToken(token);
}
static void error(Parser* parser, const char* format, ...)
{
parser->hasError = 1;
printf("Parse error on '");
printToken(parser->source, parser->current);
printf("': ");
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
printf("\n");
}

View File

@ -1,90 +0,0 @@
#ifndef wren_parser_h
#define wren_parser_h
#include "lexer.h"
// AST nodes.
typedef enum
{
NODE_LITERAL,
NODE_SEQUENCE,
NODE_CALL,
NODE_BINARY_OP,
NODE_IF,
NODE_VAR,
NODE_MAX
} NodeType;
typedef struct
{
NodeType type;
} Node;
typedef struct NodeList_s
{
Node* node;
struct NodeList_s* next;
} NodeList;
// Numbers, strings, variable names.
typedef struct
{
Node node;
Token* token;
} NodeLiteral;
typedef struct
{
Node node;
NodeList* nodes;
} NodeSequence;
typedef struct
{
Node node;
Node* fn;
NodeList* args;
} NodeCall;
typedef struct
{
Node node;
Token* op;
Node* left;
Node* right;
} NodeBinaryOp;
typedef struct
{
Node node;
Node* condition;
Node* thenArm;
Node* elseArm;
} NodeIf;
typedef struct
{
Node node;
Token* name;
Node* initializer;
} NodeVar;
// Parameters.
// TODO(bob): Is this needed?
typedef struct
{
Token* name;
} Param;
typedef struct ParamList_s
{
Param* param;
struct ParamList_s* next;
} ParamList;
Node* parse(Buffer* source, Token* tokens);
#endif

View File

@ -50,8 +50,6 @@ typedef enum
TOKEN_LINE,
TOKEN_WHITESPACE,
TOKEN_INDENT,
TOKEN_OUTDENT,
TOKEN_ERROR,
TOKEN_EOF,

49
src/vm.c Normal file
View File

@ -0,0 +1,49 @@
#include <stdlib.h>
#include <stdio.h>
#include "vm.h"
static Value pop(Fiber* fiber);
Fiber* newFiber()
{
Fiber* fiber = (Fiber*)malloc(sizeof(Fiber));
fiber->stackSize = 0;
return fiber;
}
Value interpret(Fiber* fiber, Block* block)
{
int ip = 0;
for (;;)
{
switch (block->bytecode[ip++])
{
case CODE_CONSTANT:
{
Value value = block->constants[block->bytecode[ip++]];
fiber->stack[fiber->stackSize++] = value;
break;
}
case CODE_END:
return pop(fiber);
}
}
}
void printValue(Value value)
{
switch (value->type)
{
case OBJ_INT:
printf("%d", value->value);
break;
}
}
Value pop(Fiber* fiber)
{
return fiber->stack[--fiber->stackSize];
}

57
src/vm.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef wren_vm_h
#define wren_vm_h
// TODO(bob): Make this externally controllable.
#define STACK_SIZE 1024
typedef enum {
OBJ_INT
} ObjType;
typedef enum
{
// The object has been marked during the mark phase of GC.
FLAG_MARKED = 0x01,
} ObjFlags;
typedef struct sObj {
ObjType type;
ObjFlags flags;
union {
/* OBJ_INT */
int value;
};
} Obj;
typedef Obj* Value;
typedef struct
{
Value stack[STACK_SIZE];
int stackSize;
} Fiber;
typedef enum
{
CODE_CONSTANT,
// Load the constant at index [arg].
CODE_END
// The current block is done and should be exited.
} Code;
typedef struct
{
unsigned char* bytecode;
Value* constants;
int numConstants;
} Block;
Fiber* newFiber();
Value interpret(Fiber* fiber, Block* block);
void printValue(Value value);
#endif

View File

@ -9,8 +9,9 @@
/* Begin PBXBuildFile section */
29AB1F281816E49C004B501E /* lexer.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F1E1816E49C004B501E /* lexer.c */; };
29AB1F291816E49C004B501E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F201816E49C004B501E /* main.c */; };
29AB1F2A1816E49C004B501E /* parser.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F211816E49C004B501E /* parser.c */; };
29AB1F2C1816E49C004B501E /* token.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F251816E49C004B501E /* token.c */; };
29AB1F2F1816FA66004B501E /* vm.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F2E1816FA66004B501E /* vm.c */; };
29AB1F3218170104004B501E /* compiler.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F3018170104004B501E /* compiler.c */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@ -30,11 +31,13 @@
29AB1F1E1816E49C004B501E /* lexer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = lexer.c; path = src/lexer.c; sourceTree = SOURCE_ROOT; };
29AB1F1F1816E49C004B501E /* lexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = lexer.h; path = src/lexer.h; sourceTree = SOURCE_ROOT; };
29AB1F201816E49C004B501E /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = src/main.c; sourceTree = SOURCE_ROOT; };
29AB1F211816E49C004B501E /* parser.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = parser.c; path = src/parser.c; sourceTree = SOURCE_ROOT; };
29AB1F221816E49C004B501E /* parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = parser.h; path = src/parser.h; sourceTree = SOURCE_ROOT; };
29AB1F251816E49C004B501E /* token.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = token.c; path = src/token.c; sourceTree = SOURCE_ROOT; };
29AB1F261816E49C004B501E /* token.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = token.h; path = src/token.h; sourceTree = SOURCE_ROOT; };
29AB1F271816E49C004B501E /* wren.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = wren.1; path = src/wren.1; sourceTree = SOURCE_ROOT; };
29AB1F2D1816FA5B004B501E /* vm.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = vm.h; path = src/vm.h; sourceTree = SOURCE_ROOT; };
29AB1F2E1816FA66004B501E /* vm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vm.c; path = src/vm.c; sourceTree = SOURCE_ROOT; };
29AB1F3018170104004B501E /* compiler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = compiler.c; path = src/compiler.c; sourceTree = SOURCE_ROOT; };
29AB1F3118170104004B501E /* compiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = compiler.h; path = src/compiler.h; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -67,13 +70,15 @@
29AB1F081816E3AD004B501E /* src */ = {
isa = PBXGroup;
children = (
29AB1F3018170104004B501E /* compiler.c */,
29AB1F3118170104004B501E /* compiler.h */,
29AB1F1E1816E49C004B501E /* lexer.c */,
29AB1F1F1816E49C004B501E /* lexer.h */,
29AB1F201816E49C004B501E /* main.c */,
29AB1F211816E49C004B501E /* parser.c */,
29AB1F221816E49C004B501E /* parser.h */,
29AB1F251816E49C004B501E /* token.c */,
29AB1F261816E49C004B501E /* token.h */,
29AB1F2E1816FA66004B501E /* vm.c */,
29AB1F2D1816FA5B004B501E /* vm.h */,
29AB1F271816E49C004B501E /* wren.1 */,
);
name = src;
@ -132,7 +137,8 @@
buildActionMask = 2147483647;
files = (
29AB1F291816E49C004B501E /* main.c in Sources */,
29AB1F2A1816E49C004B501E /* parser.c in Sources */,
29AB1F3218170104004B501E /* compiler.c in Sources */,
29AB1F2F1816FA66004B501E /* vm.c in Sources */,
29AB1F2C1816E49C004B501E /* token.c in Sources */,
29AB1F281816E49C004B501E /* lexer.c in Sources */,
);
@ -212,6 +218,8 @@
29AB1F101816E3AD004B501E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_C_LANGUAGE_STANDARD = c89;
GCC_WARN_PEDANTIC = NO;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
@ -219,6 +227,8 @@
29AB1F111816E3AD004B501E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_C_LANGUAGE_STANDARD = c89;
GCC_WARN_PEDANTIC = NO;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;