forked from Mirror/wren
Initial commit.
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Output directory.
|
||||||
|
build/
|
||||||
|
|
||||||
|
# XCode user-specific stuff.
|
||||||
|
xcuserdata/
|
||||||
1
example/hello.wren
Normal file
1
example/hello.wren
Normal file
@ -0,0 +1 @@
|
|||||||
|
123(1, true, "a string".whatevs)
|
||||||
233
src/lexer.c
Normal file
233
src/lexer.c
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "lexer.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Buffer* source;
|
||||||
|
|
||||||
|
int start; // The beginning of the current token.
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
Token* head;
|
||||||
|
Token* tail;
|
||||||
|
|
||||||
|
} Lexer;
|
||||||
|
|
||||||
|
static void readName(Lexer* lexer);
|
||||||
|
static void readNumber(Lexer* lexer);
|
||||||
|
static void readString(Lexer* lexer);
|
||||||
|
static void readEmbedded(Lexer* lexer);
|
||||||
|
static void readWhitespace(Lexer* lexer);
|
||||||
|
static int isKeyword(Lexer* lexer, const char* keyword);
|
||||||
|
static int isName(char c);
|
||||||
|
static int isDigit(char c);
|
||||||
|
static char advance(Lexer* lexer);
|
||||||
|
static char peek(Lexer* lexer);
|
||||||
|
static void emitToken(Lexer* lexer, TokenType type);
|
||||||
|
|
||||||
|
Token* tokenize(Buffer* source)
|
||||||
|
{
|
||||||
|
Lexer lexer;
|
||||||
|
lexer.source = source;
|
||||||
|
lexer.start = 0;
|
||||||
|
lexer.pos = 0;
|
||||||
|
lexer.head = NULL;
|
||||||
|
lexer.tail = NULL;
|
||||||
|
|
||||||
|
while (peek(&lexer) != '\0')
|
||||||
|
{
|
||||||
|
lexer.start = lexer.pos;
|
||||||
|
|
||||||
|
char c = advance(&lexer);
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '(': emitToken(&lexer, TOKEN_LEFT_PAREN); break;
|
||||||
|
case ')': emitToken(&lexer, TOKEN_RIGHT_PAREN); break;
|
||||||
|
case '[': emitToken(&lexer, TOKEN_LEFT_BRACKET); break;
|
||||||
|
case ']': emitToken(&lexer, TOKEN_RIGHT_BRACKET); break;
|
||||||
|
case '{': emitToken(&lexer, TOKEN_LEFT_BRACE); break;
|
||||||
|
case '}': emitToken(&lexer, TOKEN_RIGHT_BRACE); break;
|
||||||
|
case ':': emitToken(&lexer, TOKEN_COLON); break;
|
||||||
|
case '.': emitToken(&lexer, TOKEN_DOT); break;
|
||||||
|
case ',': emitToken(&lexer, TOKEN_COMMA); break;
|
||||||
|
case '*': emitToken(&lexer, TOKEN_STAR); break;
|
||||||
|
case '/': emitToken(&lexer, TOKEN_SLASH); break;
|
||||||
|
case '%': emitToken(&lexer, TOKEN_PERCENT); break;
|
||||||
|
case '+': emitToken(&lexer, TOKEN_PLUS); break;
|
||||||
|
case '-': emitToken(&lexer, TOKEN_MINUS); break;
|
||||||
|
case '|': emitToken(&lexer, TOKEN_PIPE); break;
|
||||||
|
case '&': emitToken(&lexer, TOKEN_AMP); break;
|
||||||
|
case '=':
|
||||||
|
if (peek(&lexer) == '=')
|
||||||
|
{
|
||||||
|
advance(&lexer);
|
||||||
|
emitToken(&lexer, TOKEN_EQEQ);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emitToken(&lexer, TOKEN_EQ);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '<':
|
||||||
|
if (peek(&lexer) == '=')
|
||||||
|
{
|
||||||
|
advance(&lexer);
|
||||||
|
emitToken(&lexer, TOKEN_LTEQ);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emitToken(&lexer, TOKEN_LT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '>':
|
||||||
|
if (peek(&lexer) == '=')
|
||||||
|
{
|
||||||
|
advance(&lexer);
|
||||||
|
emitToken(&lexer, TOKEN_GTEQ);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emitToken(&lexer, TOKEN_GT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '!':
|
||||||
|
if (peek(&lexer) == '=')
|
||||||
|
{
|
||||||
|
advance(&lexer);
|
||||||
|
emitToken(&lexer, TOKEN_BANGEQ);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emitToken(&lexer, TOKEN_BANG);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\n': emitToken(&lexer, TOKEN_LINE); break;
|
||||||
|
|
||||||
|
case ' ': readWhitespace(&lexer); break;
|
||||||
|
case '"': readString(&lexer); break;
|
||||||
|
case '`': readEmbedded(&lexer); break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (isName(c))
|
||||||
|
{
|
||||||
|
readName(&lexer);
|
||||||
|
}
|
||||||
|
else if (isDigit(c))
|
||||||
|
{
|
||||||
|
readNumber(&lexer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emitToken(&lexer, TOKEN_ERROR);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lexer.start = lexer.pos;
|
||||||
|
emitToken(&lexer, TOKEN_EOF);
|
||||||
|
|
||||||
|
return lexer.head;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void readName(Lexer* lexer)
|
||||||
|
{
|
||||||
|
// TODO(bob): Handle digits and EOF.
|
||||||
|
while (isName(peek(lexer)) || isDigit(peek(lexer))) advance(lexer);
|
||||||
|
|
||||||
|
TokenType type = TOKEN_NAME;
|
||||||
|
|
||||||
|
if (isKeyword(lexer, "else")) type = TOKEN_ELSE;
|
||||||
|
else if (isKeyword(lexer, "if")) type = TOKEN_IF;
|
||||||
|
else if (isKeyword(lexer, "var")) type = TOKEN_VAR;
|
||||||
|
|
||||||
|
emitToken(lexer, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int isKeyword(Lexer* lexer, const char* keyword)
|
||||||
|
{
|
||||||
|
size_t length = lexer->pos - lexer->start;
|
||||||
|
size_t keywordLength = strlen(keyword);
|
||||||
|
return length == keywordLength &&
|
||||||
|
strncmp(lexer->source->bytes + lexer->start, keyword, length) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void readNumber(Lexer* lexer)
|
||||||
|
{
|
||||||
|
// TODO(bob): Floating point, hex, scientific, etc.
|
||||||
|
while (isDigit(peek(lexer))) advance(lexer);
|
||||||
|
|
||||||
|
emitToken(lexer, TOKEN_NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void readString(Lexer* lexer)
|
||||||
|
{
|
||||||
|
// TODO(bob): Escape sequences, EOL, EOF, etc.
|
||||||
|
while (advance(lexer) != '"');
|
||||||
|
|
||||||
|
emitToken(lexer, TOKEN_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void readEmbedded(Lexer* lexer)
|
||||||
|
{
|
||||||
|
// TODO(bob): EOF.
|
||||||
|
while (advance(lexer) != '`');
|
||||||
|
|
||||||
|
emitToken(lexer, TOKEN_EMBEDDED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void readWhitespace(Lexer* lexer)
|
||||||
|
{
|
||||||
|
while (peek(lexer) == ' ') advance(lexer);
|
||||||
|
|
||||||
|
emitToken(lexer, TOKEN_WHITESPACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int isName(char c)
|
||||||
|
{
|
||||||
|
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
static int isDigit(char c)
|
||||||
|
{
|
||||||
|
return c >= '0' && c <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
|
static char advance(Lexer* lexer)
|
||||||
|
{
|
||||||
|
char c = peek(lexer);
|
||||||
|
lexer->pos++;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char peek(Lexer* lexer)
|
||||||
|
{
|
||||||
|
return lexer->source->bytes[lexer->pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emitToken(Lexer* lexer, TokenType type)
|
||||||
|
{
|
||||||
|
Token* token = newToken(type, lexer->start, lexer->pos);
|
||||||
|
|
||||||
|
token->prev = lexer->tail;
|
||||||
|
token->next = NULL;
|
||||||
|
|
||||||
|
if (lexer->tail == NULL)
|
||||||
|
{
|
||||||
|
// First token.
|
||||||
|
lexer->head = token;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Not the first token, so add it to the end.
|
||||||
|
lexer->tail->next = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
lexer->tail = token;
|
||||||
|
}
|
||||||
8
src/lexer.h
Normal file
8
src/lexer.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef wren_lexer_h
|
||||||
|
#define wren_lexer_h
|
||||||
|
|
||||||
|
#include "token.h"
|
||||||
|
|
||||||
|
Token* tokenize(Buffer* source);
|
||||||
|
|
||||||
|
#endif
|
||||||
71
src/main.c
Normal file
71
src/main.c
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "lexer.h"
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
#define MAX_FILE_SIZE 256 * 256
|
||||||
|
|
||||||
|
static void dumpTokens(Buffer* buffer, Token* token);
|
||||||
|
|
||||||
|
Buffer* readFile(const char* path)
|
||||||
|
{
|
||||||
|
FILE* file = fopen(path, "r");
|
||||||
|
// TODO(bob): Handle error.
|
||||||
|
|
||||||
|
Buffer* buffer = newBuffer(MAX_FILE_SIZE);
|
||||||
|
// TODO(bob): Hacky way to read a file!
|
||||||
|
size_t read = fread(buffer->bytes, sizeof(char), MAX_FILE_SIZE, file);
|
||||||
|
buffer->bytes[read] = '\0';
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char * argv[])
|
||||||
|
{
|
||||||
|
// TODO(bob): Validate command line arguments.
|
||||||
|
Buffer* buffer = readFile(argv[1]);
|
||||||
|
Token* tokens = tokenize(buffer);
|
||||||
|
//printf("Raw tokens:\n");
|
||||||
|
//dumpTokens(buffer, tokens);
|
||||||
|
//printf("Cleaned tokens:\n");
|
||||||
|
dumpTokens(buffer, tokens);
|
||||||
|
|
||||||
|
/*Node* node =*/ parse(buffer, tokens);
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (defns) generate(buffer, defns);
|
||||||
|
|
||||||
|
// TODO(bob): Free tokens.
|
||||||
|
// TODO(bob): Free ast.
|
||||||
|
*/
|
||||||
|
|
||||||
|
freeBuffer(buffer);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dumpTokens(Buffer* buffer, Token* token)
|
||||||
|
{
|
||||||
|
while (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;
|
||||||
|
default:
|
||||||
|
printf("⊏");
|
||||||
|
for (int i = token->start; i < token->end; i++)
|
||||||
|
{
|
||||||
|
putchar(buffer->bytes[i]);
|
||||||
|
}
|
||||||
|
printf("⊐");
|
||||||
|
}
|
||||||
|
token = token->next;
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
349
src/parser.c
Normal file
349
src/parser.c
Normal file
@ -0,0 +1,349 @@
|
|||||||
|
#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
Normal file
90
src/parser.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#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
|
||||||
49
src/token.c
Normal file
49
src/token.c
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "token.h"
|
||||||
|
|
||||||
|
Buffer* newBuffer(size_t size)
|
||||||
|
{
|
||||||
|
Buffer* buffer = (Buffer*)malloc(sizeof(Buffer));
|
||||||
|
buffer->bytes = (char*)malloc(size);
|
||||||
|
buffer->size = size;
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeBuffer(Buffer* buffer)
|
||||||
|
{
|
||||||
|
free(buffer->bytes);
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
Token* newToken(TokenType type, int start, int end)
|
||||||
|
{
|
||||||
|
Token* token = (Token*)malloc(sizeof(Token));
|
||||||
|
token->type = type;
|
||||||
|
token->start = start;
|
||||||
|
token->end = end;
|
||||||
|
token->prev = NULL;
|
||||||
|
token->next = NULL;
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printToken(Buffer* buffer, Token* token)
|
||||||
|
{
|
||||||
|
for (int i = token->start; i < token->end; i++)
|
||||||
|
{
|
||||||
|
putchar(buffer->bytes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Token* unlinkToken(Token* token)
|
||||||
|
{
|
||||||
|
if (token->next) token->next->prev = token->prev;
|
||||||
|
if (token->prev) token->prev->next = token->next;
|
||||||
|
|
||||||
|
token->next = NULL;
|
||||||
|
token->prev = NULL;
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
84
src/token.h
Normal file
84
src/token.h
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#ifndef wren_token_h
|
||||||
|
#define wren_token_h
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// TODO(bob): Move somewhere else?
|
||||||
|
typedef struct Buffer_s
|
||||||
|
{
|
||||||
|
char* bytes;
|
||||||
|
size_t size;
|
||||||
|
} Buffer;
|
||||||
|
|
||||||
|
// Note: if you add new token types, make sure to update the parser arrays in
|
||||||
|
// parser.c.
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
TOKEN_LEFT_PAREN,
|
||||||
|
TOKEN_RIGHT_PAREN,
|
||||||
|
TOKEN_LEFT_BRACKET,
|
||||||
|
TOKEN_RIGHT_BRACKET,
|
||||||
|
TOKEN_LEFT_BRACE,
|
||||||
|
TOKEN_RIGHT_BRACE,
|
||||||
|
TOKEN_COLON,
|
||||||
|
TOKEN_DOT,
|
||||||
|
TOKEN_COMMA,
|
||||||
|
TOKEN_STAR,
|
||||||
|
TOKEN_SLASH,
|
||||||
|
TOKEN_PERCENT,
|
||||||
|
TOKEN_PLUS,
|
||||||
|
TOKEN_MINUS,
|
||||||
|
TOKEN_PIPE,
|
||||||
|
TOKEN_AMP,
|
||||||
|
TOKEN_BANG,
|
||||||
|
TOKEN_EQ,
|
||||||
|
TOKEN_LT,
|
||||||
|
TOKEN_GT,
|
||||||
|
TOKEN_LTEQ,
|
||||||
|
TOKEN_GTEQ,
|
||||||
|
TOKEN_EQEQ,
|
||||||
|
TOKEN_BANGEQ,
|
||||||
|
|
||||||
|
TOKEN_ELSE,
|
||||||
|
TOKEN_IF,
|
||||||
|
TOKEN_VAR,
|
||||||
|
|
||||||
|
TOKEN_EMBEDDED,
|
||||||
|
TOKEN_NAME,
|
||||||
|
TOKEN_NUMBER,
|
||||||
|
TOKEN_STRING,
|
||||||
|
|
||||||
|
TOKEN_LINE,
|
||||||
|
TOKEN_WHITESPACE,
|
||||||
|
TOKEN_INDENT,
|
||||||
|
TOKEN_OUTDENT,
|
||||||
|
|
||||||
|
TOKEN_ERROR,
|
||||||
|
TOKEN_EOF,
|
||||||
|
|
||||||
|
MAX_TOKEN
|
||||||
|
} TokenType;
|
||||||
|
|
||||||
|
typedef struct Token_s
|
||||||
|
{
|
||||||
|
TokenType type;
|
||||||
|
int start;
|
||||||
|
int end;
|
||||||
|
|
||||||
|
struct Token_s* prev;
|
||||||
|
struct Token_s* next;
|
||||||
|
} Token;
|
||||||
|
|
||||||
|
Buffer* newBuffer(size_t size);
|
||||||
|
void freeBuffer(Buffer* buffer);
|
||||||
|
|
||||||
|
// Creates a new unlinked token.
|
||||||
|
Token* newToken(TokenType type, int start, int end);
|
||||||
|
|
||||||
|
// Prints the verbatim source text of the token.
|
||||||
|
void printToken(Buffer* buffer, Token* token);
|
||||||
|
|
||||||
|
// Removes the token from the list containing it. Does not free it.
|
||||||
|
Token* unlinkToken(Token* token);
|
||||||
|
|
||||||
|
#endif
|
||||||
79
src/wren.1
Normal file
79
src/wren.1
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.
|
||||||
|
.\"See Also:
|
||||||
|
.\"man mdoc.samples for a complete listing of options
|
||||||
|
.\"man mdoc for the short list of editing options
|
||||||
|
.\"/usr/share/misc/mdoc.template
|
||||||
|
.Dd 10/22/13 \" DATE
|
||||||
|
.Dt wren 1 \" Program name and manual section number
|
||||||
|
.Os Darwin
|
||||||
|
.Sh NAME \" Section Header - required - don't modify
|
||||||
|
.Nm wren,
|
||||||
|
.\" The following lines are read in generating the apropos(man -k) database. Use only key
|
||||||
|
.\" words here as the database is built based on the words here and in the .ND line.
|
||||||
|
.Nm Other_name_for_same_program(),
|
||||||
|
.Nm Yet another name for the same program.
|
||||||
|
.\" Use .Nm macro to designate other names for the documented program.
|
||||||
|
.Nd This line parsed for whatis database.
|
||||||
|
.Sh SYNOPSIS \" Section Header - required - don't modify
|
||||||
|
.Nm
|
||||||
|
.Op Fl abcd \" [-abcd]
|
||||||
|
.Op Fl a Ar path \" [-a path]
|
||||||
|
.Op Ar file \" [file]
|
||||||
|
.Op Ar \" [file ...]
|
||||||
|
.Ar arg0 \" Underlined argument - use .Ar anywhere to underline
|
||||||
|
arg2 ... \" Arguments
|
||||||
|
.Sh DESCRIPTION \" Section Header - required - don't modify
|
||||||
|
Use the .Nm macro to refer to your program throughout the man page like such:
|
||||||
|
.Nm
|
||||||
|
Underlining is accomplished with the .Ar macro like this:
|
||||||
|
.Ar underlined text .
|
||||||
|
.Pp \" Inserts a space
|
||||||
|
A list of items with descriptions:
|
||||||
|
.Bl -tag -width -indent \" Begins a tagged list
|
||||||
|
.It item a \" Each item preceded by .It macro
|
||||||
|
Description of item a
|
||||||
|
.It item b
|
||||||
|
Description of item b
|
||||||
|
.El \" Ends the list
|
||||||
|
.Pp
|
||||||
|
A list of flags and their descriptions:
|
||||||
|
.Bl -tag -width -indent \" Differs from above in tag removed
|
||||||
|
.It Fl a \"-a flag as a list item
|
||||||
|
Description of -a flag
|
||||||
|
.It Fl b
|
||||||
|
Description of -b flag
|
||||||
|
.El \" Ends the list
|
||||||
|
.Pp
|
||||||
|
.\" .Sh ENVIRONMENT \" May not be needed
|
||||||
|
.\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1
|
||||||
|
.\" .It Ev ENV_VAR_1
|
||||||
|
.\" Description of ENV_VAR_1
|
||||||
|
.\" .It Ev ENV_VAR_2
|
||||||
|
.\" Description of ENV_VAR_2
|
||||||
|
.\" .El
|
||||||
|
.Sh FILES \" File used or created by the topic of the man page
|
||||||
|
.Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact
|
||||||
|
.It Pa /usr/share/file_name
|
||||||
|
FILE_1 description
|
||||||
|
.It Pa /Users/joeuser/Library/really_long_file_name
|
||||||
|
FILE_2 description
|
||||||
|
.El \" Ends the list
|
||||||
|
.\" .Sh DIAGNOSTICS \" May not be needed
|
||||||
|
.\" .Bl -diag
|
||||||
|
.\" .It Diagnostic Tag
|
||||||
|
.\" Diagnostic informtion here.
|
||||||
|
.\" .It Diagnostic Tag
|
||||||
|
.\" Diagnostic informtion here.
|
||||||
|
.\" .El
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.\" List links in ascending order by section, alphabetically within a section.
|
||||||
|
.\" Please do not reference files that do not exist without filing a bug report
|
||||||
|
.Xr a 1 ,
|
||||||
|
.Xr b 1 ,
|
||||||
|
.Xr c 1 ,
|
||||||
|
.Xr a 2 ,
|
||||||
|
.Xr b 2 ,
|
||||||
|
.Xr a 3 ,
|
||||||
|
.Xr b 3
|
||||||
|
.\" .Sh BUGS \" Document known, unremedied bugs
|
||||||
|
.\" .Sh HISTORY \" Document history if command behaves in a unique manner
|
||||||
249
wren.xcodeproj/project.pbxproj
Normal file
249
wren.xcodeproj/project.pbxproj
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 46;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* 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 */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
29AB1F041816E3AD004B501E /* CopyFiles */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
dstPath = /usr/share/man/man1/;
|
||||||
|
dstSubfolderSpec = 0;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 1;
|
||||||
|
};
|
||||||
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
29AB1F061816E3AD004B501E /* wren */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = wren; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
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; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
29AB1F031816E3AD004B501E /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
29AB1EFD1816E3AD004B501E = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
29AB1F081816E3AD004B501E /* src */,
|
||||||
|
29AB1F071816E3AD004B501E /* Products */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
29AB1F071816E3AD004B501E /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
29AB1F061816E3AD004B501E /* wren */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
29AB1F081816E3AD004B501E /* src */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
29AB1F1E1816E49C004B501E /* lexer.c */,
|
||||||
|
29AB1F1F1816E49C004B501E /* lexer.h */,
|
||||||
|
29AB1F201816E49C004B501E /* main.c */,
|
||||||
|
29AB1F211816E49C004B501E /* parser.c */,
|
||||||
|
29AB1F221816E49C004B501E /* parser.h */,
|
||||||
|
29AB1F251816E49C004B501E /* token.c */,
|
||||||
|
29AB1F261816E49C004B501E /* token.h */,
|
||||||
|
29AB1F271816E49C004B501E /* wren.1 */,
|
||||||
|
);
|
||||||
|
name = src;
|
||||||
|
path = wren;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
29AB1F051816E3AD004B501E /* wren */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 29AB1F0F1816E3AD004B501E /* Build configuration list for PBXNativeTarget "wren" */;
|
||||||
|
buildPhases = (
|
||||||
|
29AB1F021816E3AD004B501E /* Sources */,
|
||||||
|
29AB1F031816E3AD004B501E /* Frameworks */,
|
||||||
|
29AB1F041816E3AD004B501E /* CopyFiles */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = wren;
|
||||||
|
productName = wren;
|
||||||
|
productReference = 29AB1F061816E3AD004B501E /* wren */;
|
||||||
|
productType = "com.apple.product-type.tool";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
29AB1EFE1816E3AD004B501E /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
LastUpgradeCheck = 0500;
|
||||||
|
ORGANIZATIONNAME = "Bob Nystrom";
|
||||||
|
};
|
||||||
|
buildConfigurationList = 29AB1F011816E3AD004B501E /* Build configuration list for PBXProject "wren" */;
|
||||||
|
compatibilityVersion = "Xcode 3.2";
|
||||||
|
developmentRegion = English;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
);
|
||||||
|
mainGroup = 29AB1EFD1816E3AD004B501E;
|
||||||
|
productRefGroup = 29AB1F071816E3AD004B501E /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
29AB1F051816E3AD004B501E /* wren */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
29AB1F021816E3AD004B501E /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
29AB1F291816E49C004B501E /* main.c in Sources */,
|
||||||
|
29AB1F2A1816E49C004B501E /* parser.c in Sources */,
|
||||||
|
29AB1F2C1816E49C004B501E /* token.c in Sources */,
|
||||||
|
29AB1F281816E49C004B501E /* lexer.c in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
29AB1F0D1816E3AD004B501E /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = macosx;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
29AB1F0E1816E3AD004B501E /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
COPY_PHASE_STRIP = YES;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||||
|
SDKROOT = macosx;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
29AB1F101816E3AD004B501E /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
29AB1F111816E3AD004B501E /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
29AB1F011816E3AD004B501E /* Build configuration list for PBXProject "wren" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
29AB1F0D1816E3AD004B501E /* Debug */,
|
||||||
|
29AB1F0E1816E3AD004B501E /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
29AB1F0F1816E3AD004B501E /* Build configuration list for PBXNativeTarget "wren" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
29AB1F101816E3AD004B501E /* Debug */,
|
||||||
|
29AB1F111816E3AD004B501E /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = 29AB1EFE1816E3AD004B501E /* Project object */;
|
||||||
|
}
|
||||||
7
wren.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
wren.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:wren.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
Reference in New Issue
Block a user