1
0
forked from Mirror/wren

Initial commit.

This commit is contained in:
Bob Nystrom
2013-10-22 11:22:22 -07:00
commit 2f6a6889f1
12 changed files with 1225 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
# Output directory.
build/
# XCode user-specific stuff.
xcuserdata/

1
example/hello.wren Normal file
View File

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

233
src/lexer.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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 */;
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:wren.xcodeproj">
</FileRef>
</Workspace>