forked from Mirror/wren
Start sketching out single-pass compiler.
This commit is contained in:
@ -1 +1 @@
|
|||||||
123(1, true, "a string".whatevs)
|
2
|
||||||
|
|||||||
373
src/compiler.c
Normal file
373
src/compiler.c
Normal 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
9
src/compiler.h
Normal 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
|
||||||
16
src/main.c
16
src/main.c
@ -1,8 +1,9 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "compiler.h"
|
||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
#include "parser.h"
|
#include "vm.h"
|
||||||
|
|
||||||
#define MAX_FILE_SIZE 256 * 256
|
#define MAX_FILE_SIZE 256 * 256
|
||||||
|
|
||||||
@ -32,14 +33,13 @@ int main(int argc, const char * argv[])
|
|||||||
//printf("Cleaned tokens:\n");
|
//printf("Cleaned tokens:\n");
|
||||||
dumpTokens(buffer, tokens);
|
dumpTokens(buffer, tokens);
|
||||||
|
|
||||||
/*Node* node =*/ parse(buffer, tokens);
|
Block* block = compile(buffer, tokens);
|
||||||
|
Fiber* fiber = newFiber();
|
||||||
/*
|
Value value = interpret(fiber, block);
|
||||||
if (defns) generate(buffer, defns);
|
printValue(value);
|
||||||
|
|
||||||
// TODO(bob): Free tokens.
|
// TODO(bob): Free tokens.
|
||||||
// TODO(bob): Free ast.
|
// TODO(bob): Free ast.
|
||||||
*/
|
|
||||||
|
|
||||||
freeBuffer(buffer);
|
freeBuffer(buffer);
|
||||||
|
|
||||||
@ -52,8 +52,6 @@ static void dumpTokens(Buffer* buffer, Token* token)
|
|||||||
{
|
{
|
||||||
switch (token->type)
|
switch (token->type)
|
||||||
{
|
{
|
||||||
case TOKEN_INDENT: printf("(in)"); break;
|
|
||||||
case TOKEN_OUTDENT: printf("(out)"); break;
|
|
||||||
case TOKEN_LINE: printf("(line)"); break;
|
case TOKEN_LINE: printf("(line)"); break;
|
||||||
case TOKEN_ERROR: printf("(error)"); break;
|
case TOKEN_ERROR: printf("(error)"); break;
|
||||||
case TOKEN_EOF: printf("(eof)"); break;
|
case TOKEN_EOF: printf("(eof)"); break;
|
||||||
|
|||||||
349
src/parser.c
349
src/parser.c
@ -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");
|
|
||||||
}
|
|
||||||
90
src/parser.h
90
src/parser.h
@ -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
|
|
||||||
@ -50,8 +50,6 @@ typedef enum
|
|||||||
|
|
||||||
TOKEN_LINE,
|
TOKEN_LINE,
|
||||||
TOKEN_WHITESPACE,
|
TOKEN_WHITESPACE,
|
||||||
TOKEN_INDENT,
|
|
||||||
TOKEN_OUTDENT,
|
|
||||||
|
|
||||||
TOKEN_ERROR,
|
TOKEN_ERROR,
|
||||||
TOKEN_EOF,
|
TOKEN_EOF,
|
||||||
|
|||||||
49
src/vm.c
Normal file
49
src/vm.c
Normal 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
57
src/vm.h
Normal 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
|
||||||
@ -9,8 +9,9 @@
|
|||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
29AB1F281816E49C004B501E /* lexer.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F1E1816E49C004B501E /* lexer.c */; };
|
29AB1F281816E49C004B501E /* lexer.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F1E1816E49C004B501E /* lexer.c */; };
|
||||||
29AB1F291816E49C004B501E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F201816E49C004B501E /* main.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 */; };
|
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 */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase 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; };
|
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; };
|
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; };
|
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; };
|
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; };
|
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; };
|
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 */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -67,13 +70,15 @@
|
|||||||
29AB1F081816E3AD004B501E /* src */ = {
|
29AB1F081816E3AD004B501E /* src */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
29AB1F3018170104004B501E /* compiler.c */,
|
||||||
|
29AB1F3118170104004B501E /* compiler.h */,
|
||||||
29AB1F1E1816E49C004B501E /* lexer.c */,
|
29AB1F1E1816E49C004B501E /* lexer.c */,
|
||||||
29AB1F1F1816E49C004B501E /* lexer.h */,
|
29AB1F1F1816E49C004B501E /* lexer.h */,
|
||||||
29AB1F201816E49C004B501E /* main.c */,
|
29AB1F201816E49C004B501E /* main.c */,
|
||||||
29AB1F211816E49C004B501E /* parser.c */,
|
|
||||||
29AB1F221816E49C004B501E /* parser.h */,
|
|
||||||
29AB1F251816E49C004B501E /* token.c */,
|
29AB1F251816E49C004B501E /* token.c */,
|
||||||
29AB1F261816E49C004B501E /* token.h */,
|
29AB1F261816E49C004B501E /* token.h */,
|
||||||
|
29AB1F2E1816FA66004B501E /* vm.c */,
|
||||||
|
29AB1F2D1816FA5B004B501E /* vm.h */,
|
||||||
29AB1F271816E49C004B501E /* wren.1 */,
|
29AB1F271816E49C004B501E /* wren.1 */,
|
||||||
);
|
);
|
||||||
name = src;
|
name = src;
|
||||||
@ -132,7 +137,8 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
29AB1F291816E49C004B501E /* main.c in Sources */,
|
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 */,
|
29AB1F2C1816E49C004B501E /* token.c in Sources */,
|
||||||
29AB1F281816E49C004B501E /* lexer.c in Sources */,
|
29AB1F281816E49C004B501E /* lexer.c in Sources */,
|
||||||
);
|
);
|
||||||
@ -212,6 +218,8 @@
|
|||||||
29AB1F101816E3AD004B501E /* Debug */ = {
|
29AB1F101816E3AD004B501E /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
GCC_C_LANGUAGE_STANDARD = c89;
|
||||||
|
GCC_WARN_PEDANTIC = NO;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
@ -219,6 +227,8 @@
|
|||||||
29AB1F111816E3AD004B501E /* Release */ = {
|
29AB1F111816E3AD004B501E /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
GCC_C_LANGUAGE_STANDARD = c89;
|
||||||
|
GCC_WARN_PEDANTIC = NO;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
|
|||||||
Reference in New Issue
Block a user