Merge branch 'future' of github.com:justinmeza/lci into future
This commit is contained in:
commit
da61b7bcee
|
@ -0,0 +1,7 @@
|
|||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
CTestTestfile.cmake
|
||||
tags
|
|
@ -28,6 +28,7 @@ SET(HDRS
|
|||
tokenizer.h
|
||||
unicode.h
|
||||
error.h
|
||||
binding.h
|
||||
)
|
||||
|
||||
SET(SRCS
|
||||
|
@ -38,10 +39,11 @@ SET(SRCS
|
|||
tokenizer.c
|
||||
unicode.c
|
||||
error.c
|
||||
binding.c
|
||||
)
|
||||
|
||||
|
||||
add_executable(lci ${SRCS} ${HDRS})
|
||||
target_link_libraries(lci m)
|
||||
target_link_libraries(lci m ncurses readline)
|
||||
add_subdirectory(test)
|
||||
install(
|
||||
TARGETS lci
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
#include "binding.h"
|
||||
|
||||
struct returnobject;
|
||||
struct scopeobject;
|
||||
|
||||
ValueObject *getArg(struct scopeobject *scope, char *name)
|
||||
{
|
||||
IdentifierNode *id = createIdentifierNode(IT_DIRECT, (void *)copyString(name), NULL, NULL, 0);
|
||||
ValueObject *val = getScopeValueLocal(scope, scope, id);
|
||||
deleteIdentifierNode(id);
|
||||
return val;
|
||||
}
|
||||
|
||||
struct returnobject *fopenWrapper(struct scopeobject *scope)
|
||||
{
|
||||
ValueObject *arg1 = getArg(scope, "filename");
|
||||
ValueObject *arg2 = getArg(scope, "mode");
|
||||
char *filename = getString(arg1);
|
||||
char *mode = getString(arg2);
|
||||
|
||||
FILE *f = fopen(filename, mode);
|
||||
|
||||
ValueObject *ret = createBlobValueObject(f);
|
||||
return createReturnObject(RT_RETURN, ret);
|
||||
}
|
||||
|
||||
struct returnobject *freadWrapper(struct scopeobject *scope)
|
||||
{
|
||||
ValueObject *arg1 = getArg(scope, "file");
|
||||
ValueObject *arg2 = getArg(scope, "length");
|
||||
FILE *file = (FILE *)getBlob(arg1);
|
||||
int length = getInteger(arg2);
|
||||
|
||||
char *buf = malloc((sizeof(char) * length) + 1);
|
||||
fread(buf, 1, length, file);
|
||||
buf[length] = '\0';
|
||||
|
||||
ValueObject *ret = createStringValueObject(buf);
|
||||
return createReturnObject(RT_RETURN, ret);
|
||||
}
|
||||
|
||||
struct returnobject *fwriteWrapper(struct scopeobject *scope)
|
||||
{
|
||||
ValueObject *arg1 = getArg(scope, "file");
|
||||
ValueObject *arg2 = getArg(scope, "data");
|
||||
FILE *file = (FILE *)getBlob(arg1);
|
||||
char *data = getString(arg2);
|
||||
|
||||
fwrite(data, 1, strlen(data), file);
|
||||
|
||||
return createReturnObject(RT_DEFAULT, NULL);
|
||||
}
|
||||
|
||||
struct returnobject *fcloseWrapper(struct scopeobject *scope)
|
||||
{
|
||||
ValueObject *arg1 = getArg(scope, "file");
|
||||
FILE *file = (FILE *)getBlob(arg1);
|
||||
|
||||
fclose(file);
|
||||
deleteValueObject(arg1);
|
||||
|
||||
return createReturnObject(RT_DEFAULT, NULL);
|
||||
}
|
||||
|
||||
void loadLibrary(ScopeObject *scope, IdentifierNode *target)
|
||||
{
|
||||
char *name = NULL;
|
||||
int status;
|
||||
ScopeObject *lib = NULL;
|
||||
IdentifierNode *id = NULL;
|
||||
ValueObject *val = NULL;
|
||||
if (target == NULL) return;
|
||||
|
||||
name = resolveIdentifierName(target, scope);
|
||||
if (!name) goto loadLibraryAbort;
|
||||
|
||||
if (!strcmp(name, "STDIO")) {
|
||||
lib = createScopeObject(scope);
|
||||
if (!lib) goto loadLibraryAbort;
|
||||
|
||||
loadBinding(lib, "FOPENIN", "filename mode", &fopenWrapper);
|
||||
loadBinding(lib, "FREADIN", "file length", &freadWrapper);
|
||||
loadBinding(lib, "FWRITIN", "file data", &fwriteWrapper);
|
||||
loadBinding(lib, "FCLOSIN", "file", &fcloseWrapper);
|
||||
|
||||
id = createIdentifierNode(IT_DIRECT, (void *)copyString("STDIO"), NULL, NULL, 0);
|
||||
if (!id) goto loadLibraryAbort;
|
||||
|
||||
if (!createScopeValue(scope, scope, id)) goto loadLibraryAbort;
|
||||
|
||||
val = createArrayValueObject(lib);
|
||||
if (!val) goto loadLibraryAbort;
|
||||
lib = NULL;
|
||||
|
||||
if (!updateScopeValue(scope, scope, id, val)) goto loadLibraryAbort;
|
||||
}
|
||||
|
||||
if (name) free(name);
|
||||
return;
|
||||
|
||||
loadLibraryAbort: /* In case something goes wrong... */
|
||||
|
||||
/* Clean up any allocated structures */
|
||||
if (name) free(name);
|
||||
if (lib) deleteScopeObject(lib);
|
||||
if (id) deleteIdentifierNode(id);
|
||||
if (val) deleteValueObject(val);
|
||||
return;
|
||||
}
|
||||
|
||||
void loadBinding(ScopeObject *scope, char *name, const char *args, struct returnobject *(*binding)(struct scopeobject *))
|
||||
{
|
||||
IdentifierNode *id = NULL;
|
||||
StmtNodeList *stmts = NULL;
|
||||
BindingStmtNode *stmt = NULL;
|
||||
StmtNode *wrapper = NULL;
|
||||
int status;
|
||||
BlockNode *body = NULL;
|
||||
IdentifierNodeList *ids = NULL;
|
||||
IdentifierNode *arg = NULL;
|
||||
if (name == NULL || binding == NULL) return;
|
||||
|
||||
id = createIdentifierNode(IT_DIRECT, (void *)copyString(name), NULL, NULL, 0);
|
||||
if (!id) goto loadBindingAbort;
|
||||
|
||||
stmts = createStmtNodeList();
|
||||
if (!stmts) goto loadBindingAbort;
|
||||
|
||||
stmt = createBindingStmtNode(binding);
|
||||
if (!stmt) goto loadBindingAbort;
|
||||
|
||||
wrapper = createStmtNode(ST_BINDING, stmt);
|
||||
if (!wrapper) goto loadBindingAbort;
|
||||
stmt = NULL;
|
||||
|
||||
status = addStmtNode(stmts, wrapper);
|
||||
if (!status) goto loadBindingAbort;
|
||||
wrapper = NULL;
|
||||
|
||||
body = createBlockNode(stmts);
|
||||
if (!body) goto loadBindingAbort;
|
||||
stmts = NULL;
|
||||
|
||||
ids = createIdentifierNodeList();
|
||||
if (!ids) goto loadBindingAbort;
|
||||
|
||||
const char *start = args;
|
||||
while (start != NULL) {
|
||||
char *end = strchr(start, ' ');
|
||||
char *temp = NULL;
|
||||
unsigned int len = 0;
|
||||
|
||||
if (end != NULL) len = (end - start);
|
||||
else len = strlen(start);
|
||||
|
||||
temp = malloc(sizeof(char) * (len + 1));
|
||||
strncpy(temp, start, len);
|
||||
temp[len] = '\0';
|
||||
|
||||
if (end != NULL) start = (end + 1);
|
||||
else start = NULL;
|
||||
|
||||
arg = createIdentifierNode(IT_DIRECT, (void *)temp, NULL, NULL, 0);
|
||||
if (!arg) goto loadBindingAbort;
|
||||
|
||||
status = addIdentifierNode(ids, arg);
|
||||
if (!status) goto loadBindingAbort;
|
||||
}
|
||||
|
||||
FuncDefStmtNode *interface = createFuncDefStmtNode(NULL, id, ids, body);
|
||||
if (!interface) goto loadBindingAbort;
|
||||
|
||||
ValueObject *val = createFunctionValueObject(interface);
|
||||
if (!val) goto loadBindingAbort;
|
||||
|
||||
createScopeValue(scope, scope, id);
|
||||
updateScopeValue(scope, scope, id, val);
|
||||
|
||||
return;
|
||||
|
||||
loadBindingAbort: /* In case something goes wrong... */
|
||||
|
||||
if (id) deleteIdentifierNode(id);
|
||||
if (val) deleteValueObject(val);
|
||||
else if (interface) deleteFuncDefStmtNode(interface);
|
||||
else {
|
||||
if (arg) deleteIdentifierNode(arg);
|
||||
if (ids) deleteIdentifierNodeList(ids);
|
||||
if (body) deleteBlockNode(body);
|
||||
if (stmts) deleteStmtNodeList(stmts);
|
||||
if (wrapper) deleteStmtNode(wrapper);
|
||||
if (stmt) deleteBindingStmtNode(stmt);
|
||||
}
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* Structures and functions for binding to external libraries.
|
||||
*
|
||||
* \file binding.h
|
||||
*
|
||||
* \author Justin J. Meza
|
||||
*
|
||||
* \date 2013
|
||||
*/
|
||||
|
||||
#ifndef __BINDING_H__
|
||||
#define __BINDING_H__
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "interpreter.h"
|
||||
|
||||
/**
|
||||
* Stores a binding to an external library call to export.
|
||||
*/
|
||||
typedef struct {
|
||||
IdentifierNode *library; /**< The library this binding belongs to. */
|
||||
FuncDefStmtNode *interface; /**< The interface that exports the binding. */
|
||||
} Binding;
|
||||
|
||||
ValueObject *getArg(struct scopeobject *, char *);
|
||||
void loadLibrary(ScopeObject *, IdentifierNode *);
|
||||
void loadBinding(ScopeObject *, char *, const char *, struct returnobject *(*)(struct scopeobject *));
|
||||
|
||||
#endif /* __BINDING_H__ */
|
4
error.c
4
error.c
|
@ -226,12 +226,12 @@ static const int err_codes[] = {
|
|||
538, /* IN_FUNCTION_NAME_USED_BY_VARIABLE */
|
||||
};
|
||||
|
||||
void error(ErrorType e, ...)
|
||||
int error(ErrorType e, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, e);
|
||||
vfprintf(stderr, err_msgs[e], args);
|
||||
va_end(args);
|
||||
|
||||
exit(err_codes[e]);
|
||||
return err_codes[e];
|
||||
}
|
||||
|
|
2
error.h
2
error.h
|
@ -104,6 +104,6 @@ typedef enum {
|
|||
IN_FUNCTION_NAME_USED_BY_VARIABLE,
|
||||
} ErrorType;
|
||||
|
||||
void error(ErrorType, ...);
|
||||
int error(ErrorType, ...);
|
||||
|
||||
#endif /* __ERROR_H__ */
|
||||
|
|
14
install.py
14
install.py
|
@ -16,7 +16,7 @@ def positiveInt(string):
|
|||
Runs a subprocess using the command parameter.
|
||||
Before running the command it displays a message
|
||||
that contains the provided description and where
|
||||
the output will be sent. If an error occurs,
|
||||
the output will be sent. If an error occurs,
|
||||
the errorMsg is displayed.
|
||||
"""
|
||||
def runSubProc(command, description, errorMsg, output):
|
||||
|
@ -28,7 +28,7 @@ def runSubProc(command, description, errorMsg, output):
|
|||
if os.name == "nt":
|
||||
proc = subprocess.Popen(command, stdout=outputFile, stderr=subprocess.STDOUT, shell=True)
|
||||
else:
|
||||
proc = subprocess.Popen(command, stdout=outputFile, stderr=subprocess.STDOUT)
|
||||
proc = subprocess.Popen(command, stdout=outputFile, stderr=subprocess.STDOUT, shell=True)
|
||||
proc.wait()
|
||||
if proc.returncode != 0:
|
||||
print("Error installing: " + errorMsg)
|
||||
|
@ -72,7 +72,7 @@ runSubProc(
|
|||
"configure.out")
|
||||
|
||||
runSubProc(
|
||||
[makeCommand, "-j"+j],
|
||||
[makeCommand, "-j"+j],
|
||||
"Running make ",
|
||||
"There was a make error",
|
||||
"make.out")
|
||||
|
@ -80,20 +80,20 @@ runSubProc(
|
|||
|
||||
if args.buildDocs:
|
||||
runSubProc(
|
||||
[makeCommand, "-j"+j, "docs"],
|
||||
[makeCommand, "-j"+j, "docs"],
|
||||
"Building documentation ",
|
||||
"There was a documentation building error",
|
||||
"docs.out")
|
||||
|
||||
|
||||
runSubProc(
|
||||
[makeCommand, "install"],
|
||||
makeCommand + " install",
|
||||
"Installing ",
|
||||
"There was an installation error",
|
||||
"install.out")
|
||||
|
||||
if args.runTests:
|
||||
runSubProc(
|
||||
["ctest", "-j"+j],
|
||||
["ctest", "-j"+j],
|
||||
"Testing ",
|
||||
"There was a testing error",
|
||||
"test.out")
|
||||
|
|
|
@ -306,6 +306,30 @@ ValueObject *createArrayValueObject(ScopeObject *parent)
|
|||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a blob-type value.
|
||||
*
|
||||
* \param [in] data The binary blob data to store.
|
||||
*
|
||||
* \note \a data is stored as-is; no copy of it is made.
|
||||
*
|
||||
* \return A string-type value equalling \a data.
|
||||
*
|
||||
* \retval NULL Memory allocation failed.
|
||||
*/
|
||||
ValueObject *createBlobValueObject(void *data)
|
||||
{
|
||||
ValueObject *p = malloc(sizeof(ValueObject));
|
||||
if (!p) {
|
||||
perror("malloc");
|
||||
return NULL;
|
||||
}
|
||||
p->type = VT_BLOB;
|
||||
p->data.b = data;
|
||||
p->semaphore = 1;
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies a value.
|
||||
*
|
||||
|
@ -3589,7 +3613,7 @@ ReturnObject *interpretExprStmtNode(StmtNode *node,
|
|||
*
|
||||
* \param [in] scope The scope to evaluate \a node under.
|
||||
*
|
||||
* \pre \a node contains a statement created by createAltArrayDefNode().
|
||||
* \pre \a node contains a statement created by createAltArrayDefStmtNode().
|
||||
*
|
||||
* \return A pointer to a default return value.
|
||||
*
|
||||
|
@ -3639,11 +3663,52 @@ ReturnObject *interpretAltArrayDefStmtNode(StmtNode *node,
|
|||
return createReturnObject(RT_DEFAULT, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interprets a binding statement.
|
||||
*
|
||||
* \param [in] node The statement to interpret.
|
||||
*
|
||||
* \param [in] scope The scope to evaluate \a node under.
|
||||
*
|
||||
* \pre \a node contains a statement created by createBindingStmtNode().
|
||||
*
|
||||
* \return A pointer to a default return value.
|
||||
*
|
||||
* \retval NULL An error occurred during interpretation.
|
||||
*/
|
||||
ReturnObject *interpretBindingStmtNode(StmtNode *node,
|
||||
ScopeObject *scope)
|
||||
{
|
||||
BindingStmtNode *stmt = (BindingStmtNode *)node->stmt;
|
||||
return (stmt->binding)(scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interprets a library import statement.
|
||||
*
|
||||
* \param [in] node The statement to interpret.
|
||||
*
|
||||
* \param [in] scope The scope to evaluate \a node under.
|
||||
*
|
||||
* \pre \a node contains a statement created by createImportStmtNode().
|
||||
*
|
||||
* \return A pointer to a default return value.
|
||||
*
|
||||
* \retval NULL An error occurred during interpretation.
|
||||
*/
|
||||
ReturnObject *interpretImportStmtNode(StmtNode *node,
|
||||
ScopeObject *scope)
|
||||
{
|
||||
ImportStmtNode *stmt = (ImportStmtNode *)node->stmt;
|
||||
loadLibrary(scope, stmt->name);
|
||||
return createReturnObject(RT_DEFAULT, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* A jump table for statements. The index of a function in the table is given
|
||||
* by its its index in the enumerated StmtType type.
|
||||
*/
|
||||
static ReturnObject *(*StmtJumpTable[14])(StmtNode *, ScopeObject *) = {
|
||||
static ReturnObject *(*StmtJumpTable[16])(StmtNode *, ScopeObject *) = {
|
||||
interpretCastStmtNode,
|
||||
interpretPrintStmtNode,
|
||||
interpretInputStmtNode,
|
||||
|
@ -3657,7 +3722,9 @@ static ReturnObject *(*StmtJumpTable[14])(StmtNode *, ScopeObject *) = {
|
|||
interpretDeallocationStmtNode,
|
||||
interpretFuncDefStmtNode,
|
||||
interpretExprStmtNode,
|
||||
interpretAltArrayDefStmtNode };
|
||||
interpretAltArrayDefStmtNode,
|
||||
interpretBindingStmtNode,
|
||||
interpretImportStmtNode };
|
||||
|
||||
/**
|
||||
* Interprets a statement.
|
||||
|
@ -3741,6 +3808,8 @@ ReturnObject *interpretBlockNode(BlockNode *node,
|
|||
*
|
||||
* \param [in] main The main block of code to interpret.
|
||||
*
|
||||
* \param [in] scope The scope to evaluate \a main under.
|
||||
*
|
||||
* \pre \a main contains a block of code created by parseMainNode().
|
||||
*
|
||||
* \return The final status of the program.
|
||||
|
@ -3749,12 +3818,12 @@ ReturnObject *interpretBlockNode(BlockNode *node,
|
|||
*
|
||||
* \retval 1 An error occurred while interpreting \a main.
|
||||
*/
|
||||
int interpretMainNode(MainNode *main)
|
||||
int interpretMainNodeScope(MainNode *main, ScopeObject *scope)
|
||||
{
|
||||
ReturnObject *ret = NULL;
|
||||
if (!main) return 1;
|
||||
ret = interpretBlockNode(main->block, NULL);
|
||||
if (!ret) return 1;
|
||||
ret = interpretBlockNode(main->block, scope);
|
||||
if (!ret) return 1;
|
||||
deleteReturnObject(ret);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -46,6 +46,11 @@
|
|||
*/
|
||||
#define getArray(value) (value->data.a)
|
||||
|
||||
/**
|
||||
* Retrieves a value's blob data.
|
||||
*/
|
||||
#define getBlob(value) (value->data.b)
|
||||
|
||||
/**
|
||||
* Represents a value type.
|
||||
*/
|
||||
|
@ -56,7 +61,8 @@ typedef enum {
|
|||
VT_STRING, /**< A string value. */
|
||||
VT_NIL, /**< Represents no value. */
|
||||
VT_FUNC, /**< A function. */
|
||||
VT_ARRAY /**< An array. */
|
||||
VT_ARRAY, /**< An array. */
|
||||
VT_BLOB /**< A binary blob of data. */
|
||||
} ValueType;
|
||||
|
||||
/**
|
||||
|
@ -68,6 +74,7 @@ typedef union {
|
|||
char *s; /**< String data. */
|
||||
FuncDefStmtNode *fn; /**< Function data. */
|
||||
struct scopeobject *a; /**< Array data. */
|
||||
void *b; /**< Binary blob data. */
|
||||
} ValueData;
|
||||
|
||||
/**
|
||||
|
@ -101,7 +108,7 @@ typedef enum {
|
|||
/**
|
||||
* Stores return state.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct returnobject {
|
||||
ReturnType type; /**< The type of return encountered. */
|
||||
ValueObject *value; /**< The optional return value. */
|
||||
} ReturnObject;
|
||||
|
@ -144,6 +151,7 @@ ValueObject *createFloatValueObject(float);
|
|||
ValueObject *createStringValueObject(char *);
|
||||
ValueObject *createFunctionValueObject(FuncDefStmtNode *);
|
||||
ValueObject *createArrayValueObject(ScopeObject *);
|
||||
ValueObject *createBlobValueObject(void *);
|
||||
ValueObject *copyValueObject(ValueObject *);
|
||||
void deleteValueObject(ValueObject *);
|
||||
/**@}*/
|
||||
|
@ -252,6 +260,8 @@ ReturnObject *interpretDeallocationStmtNode(StmtNode *, ScopeObject *);
|
|||
ReturnObject *interpretFuncDefStmtNode(StmtNode *, ScopeObject *);
|
||||
ReturnObject *interpretExprStmtNode(StmtNode *, ScopeObject *);
|
||||
ReturnObject *interpretAltArrayDefStmtNode(StmtNode *, ScopeObject *);
|
||||
ReturnObject *interpretBindingStmtNode(StmtNode *, ScopeObject *);
|
||||
ReturnObject *interpretImportStmtNode(StmtNode *, ScopeObject *);
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
|
|
17
lexer.c
17
lexer.c
|
@ -198,6 +198,21 @@ LexemeList *scanBuffer(const char *buffer, unsigned int size, const char *fname)
|
|||
start += 2;
|
||||
continue;
|
||||
}
|
||||
/* Question mark (?) is its own lexeme */
|
||||
if (*start == '?') {
|
||||
Lexeme *lex = createLexeme("?", fname, line);
|
||||
if (!lex) {
|
||||
deleteLexemeList(list);
|
||||
return NULL;
|
||||
}
|
||||
if (!addLexeme(list, lex)) {
|
||||
deleteLexeme(lex);
|
||||
deleteLexemeList(list);
|
||||
return NULL;
|
||||
}
|
||||
start++;
|
||||
continue;
|
||||
}
|
||||
/* Skip over leading whitespace */
|
||||
while (isspace(*start)) {
|
||||
unsigned int newline = 0;
|
||||
|
@ -292,6 +307,7 @@ LexemeList *scanBuffer(const char *buffer, unsigned int size, const char *fname)
|
|||
if (start[len] && !isspace(start[len])
|
||||
&& *(start + len) != ','
|
||||
&& *(start + len) != '!'
|
||||
&& *(start + len) != '?'
|
||||
&& strncmp(start + len, "'Z", 2)
|
||||
&& strncmp(start + len, "...", 3)
|
||||
&& strncmp(start + len, "\xE2\x80\xA6", 3)) {
|
||||
|
@ -305,6 +321,7 @@ LexemeList *scanBuffer(const char *buffer, unsigned int size, const char *fname)
|
|||
while (start[len] && !isspace(start[len])
|
||||
&& *(start + len) != ','
|
||||
&& *(start + len) != '!'
|
||||
&& *(start + len) != '?'
|
||||
&& strncmp(start + len, "'Z", 2)
|
||||
&& strncmp(start + len, "...", 3)
|
||||
&& strncmp(start + len, "\xE2\x80\xA6", 3))
|
||||
|
|
105
main.c
105
main.c
|
@ -109,6 +109,8 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
|
||||
#include "lexer.h"
|
||||
#include "tokenizer.h"
|
||||
|
@ -120,10 +122,11 @@
|
|||
|
||||
static char *program_name;
|
||||
|
||||
static char *shortopt = "hv";
|
||||
static char *shortopt = "hvi";
|
||||
static struct option longopt[] = {
|
||||
{ "help", no_argument, NULL, (int)'h' },
|
||||
{ "version", no_argument, NULL, (int)'v' },
|
||||
{ "interactive", no_argument, NULL, (int)'i' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -132,26 +135,52 @@ static void help(void) {
|
|||
Usage: %s [FILE] ... \n\
|
||||
Interpret FILE(s) as LOLCODE. Let FILE be '-' for stdin.\n\
|
||||
-h, --help\t\toutput this help\n\
|
||||
-v, --version\t\tprogram version\n", program_name);
|
||||
-v, --version\t\tprogram version\n\
|
||||
-i, --interactive\tinteractive prompt\n", program_name);
|
||||
}
|
||||
|
||||
static void version (char *revision) {
|
||||
fprintf(stderr, "%s %s\n", program_name, revision);
|
||||
}
|
||||
|
||||
int pipeline(char *buffer, unsigned int length, const char *fname, ScopeObject *scope)
|
||||
{
|
||||
LexemeList *lexemes = NULL;
|
||||
Token **tokens = NULL;
|
||||
MainNode *node = NULL;
|
||||
if (!(lexemes = scanBuffer(buffer, length, fname))) {
|
||||
free(buffer);
|
||||
return 1;
|
||||
}
|
||||
free(buffer);
|
||||
if (!(tokens = tokenizeLexemes(lexemes))) {
|
||||
deleteLexemeList(lexemes);
|
||||
return 1;
|
||||
}
|
||||
deleteLexemeList(lexemes);
|
||||
if (!(node = parseMainNode(tokens))) {
|
||||
deleteTokens(tokens);
|
||||
return 1;
|
||||
}
|
||||
deleteTokens(tokens);
|
||||
if (interpretMainNodeScope(node, NULL)) {
|
||||
deleteMainNode(node);
|
||||
return 1;
|
||||
}
|
||||
deleteMainNode(node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
unsigned int length = 0;
|
||||
char *buffer = NULL;
|
||||
LexemeList *lexemes = NULL;
|
||||
Token **tokens = NULL;
|
||||
MainNode *node = NULL;
|
||||
char *fname = NULL;
|
||||
FILE *file = NULL;
|
||||
int ch;
|
||||
|
||||
char *revision = "v0.10.3";
|
||||
char *revision = "v0.11.4";
|
||||
program_name = argv[0];
|
||||
|
||||
while ((ch = getopt_long(argc, argv, shortopt, longopt, NULL)) != -1) {
|
||||
|
@ -165,15 +194,50 @@ int main(int argc, char **argv)
|
|||
case 'v':
|
||||
version(revision);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'i':
|
||||
{
|
||||
char *line = NULL;
|
||||
/* Save state between lines using a ScopeObject structure */
|
||||
ScopeObject *scope = createScopeObject(NULL);
|
||||
if (!scope) return 1;
|
||||
while (line = readline("lci> ")) {
|
||||
char *pre = "HAI 1.4\n";
|
||||
char *post = "\n\nKTHXBYE\n";
|
||||
char *code = NULL;
|
||||
size = strlen(line);
|
||||
buffer = realloc(buffer, sizeof(char) * (length + size + 1));
|
||||
strncpy(buffer + length, line, size);
|
||||
buffer[length + size] = '\n';
|
||||
length += size + 1;
|
||||
add_history(line);
|
||||
/* Intercept KTHXBYE to quit */
|
||||
if (!strcmp(line, "KTHXBYE")) {
|
||||
break;
|
||||
}
|
||||
/* Intercept HALP to display help message */
|
||||
else if (!strcmp(line, "HALP")) {
|
||||
version(revision);
|
||||
help();
|
||||
continue;
|
||||
}
|
||||
/* Create staged code file */
|
||||
code = malloc(sizeof(char) * (strlen(pre) + size + strlen(post) + 1));
|
||||
strcpy(code, pre);
|
||||
strncpy(code + strlen(pre), line, size);
|
||||
strcpy(code + strlen(pre) + size, post);
|
||||
code[strlen(pre) + size + strlen(post)] = '\0';
|
||||
pipeline(code, strlen(code), "interactive", scope);
|
||||
}
|
||||
free(buffer);
|
||||
deleteScopeObject(scope);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (; optind < argc; optind++) {
|
||||
size = length = 0;
|
||||
buffer = fname = NULL;
|
||||
lexemes = NULL;
|
||||
tokens = NULL;
|
||||
node = NULL;
|
||||
file = NULL;
|
||||
|
||||
if (!strncmp(argv[optind],"-\0",2)) {
|
||||
|
@ -228,28 +292,7 @@ int main(int argc, char **argv)
|
|||
printf("%c%c%c", 0xef, 0xbb, 0xbf);
|
||||
}
|
||||
|
||||
/* Begin main pipeline */
|
||||
if (!(lexemes = scanBuffer(buffer, length, fname))) {
|
||||
free(buffer);
|
||||
return 1;
|
||||
}
|
||||
free(buffer);
|
||||
if (!(tokens = tokenizeLexemes(lexemes))) {
|
||||
deleteLexemeList(lexemes);
|
||||
return 1;
|
||||
}
|
||||
deleteLexemeList(lexemes);
|
||||
if (!(node = parseMainNode(tokens))) {
|
||||
deleteTokens(tokens);
|
||||
return 1;
|
||||
}
|
||||
deleteTokens(tokens);
|
||||
if (interpretMainNode(node)) {
|
||||
deleteMainNode(node);
|
||||
return 1;
|
||||
}
|
||||
deleteMainNode(node);
|
||||
/* End main pipeline */
|
||||
return pipeline(buffer, length, fname, NULL);
|
||||
|
||||
}
|
||||
|
||||
|
|
165
parser.c
165
parser.c
|
@ -514,6 +514,16 @@ void deleteStmtNode(StmtNode *node)
|
|||
deleteAltArrayDefStmtNode(stmt);
|
||||
break;
|
||||
}
|
||||
case ST_BINDING: {
|
||||
BindingStmtNode *stmt = (BindingStmtNode *)node->stmt;
|
||||
deleteBindingStmtNode(stmt);
|
||||
break;
|
||||
}
|
||||
case ST_IMPORT: {
|
||||
ImportStmtNode *stmt = (ImportStmtNode *)node->stmt;
|
||||
deleteImportStmtNode(stmt);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error(PR_UNKNOWN_STATEMENT_TYPE);
|
||||
break;
|
||||
|
@ -1105,6 +1115,73 @@ void deleteAltArrayDefStmtNode(AltArrayDefStmtNode *node)
|
|||
free(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a library import statement.
|
||||
*
|
||||
* \param [in] name The name of the library to import.
|
||||
*
|
||||
* \return A pointer to a library import statement with the desired properties.
|
||||
*
|
||||
* \retval NULL Memory allocation failed.
|
||||
*/
|
||||
ImportStmtNode *createImportStmtNode(IdentifierNode *name)
|
||||
{
|
||||
ImportStmtNode *p = malloc(sizeof(ImportStmtNode));
|
||||
if (!p) {
|
||||
perror("malloc");
|
||||
return NULL;
|
||||
}
|
||||
p->name = name;
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a library import statement.
|
||||
*
|
||||
* \param [in,out] node The library import statement to delete.
|
||||
*
|
||||
* \post The memory at \a node and all of its members will be freed.
|
||||
*/
|
||||
void deleteImportStmtNode(ImportStmtNode *node)
|
||||
{
|
||||
if (!node) return;
|
||||
deleteIdentifierNode(node->name);
|
||||
free(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a binding statement.
|
||||
*
|
||||
* \param [in] binding A pointer to the function that defines the binding.
|
||||
*
|
||||
* \return A pointer to a binding statement with the desired properties.
|
||||
*
|
||||
* \retval NULL Memory allocation failed.
|
||||
*/
|
||||
BindingStmtNode *createBindingStmtNode(struct returnobject *(*binding)(struct scopeobject *))
|
||||
{
|
||||
BindingStmtNode *p = malloc(sizeof(BindingStmtNode));
|
||||
if (!p) {
|
||||
perror("malloc");
|
||||
return NULL;
|
||||
}
|
||||
p->binding = binding;
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a binding statement.
|
||||
*
|
||||
* \param [in,out] node The binding statement to delete.
|
||||
*
|
||||
* \post The memory at \a node and all of its members will be freed.
|
||||
*/
|
||||
void deleteBindingStmtNode(BindingStmtNode *node)
|
||||
{
|
||||
if (!node) return;
|
||||
free(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an expression.
|
||||
*
|
||||
|
@ -2820,6 +2897,13 @@ StmtNode *parseIfThenElseStmtNode(Token ***tokenp)
|
|||
goto parseIfThenElseStmtNodeAbort;
|
||||
}
|
||||
|
||||
/* Remove the question mark from the token stream */
|
||||
status = acceptToken(&tokens, TT_QUESTION);
|
||||
if (!status) {
|
||||
parser_error_expected_token(TT_QUESTION, tokens);
|
||||
goto parseIfThenElseStmtNodeAbort;
|
||||
}
|
||||
|
||||
/* The if keyword must appear on its own line */
|
||||
if (!acceptToken(&tokens, TT_NEWLINE)) {
|
||||
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
|
||||
|
@ -2973,6 +3057,13 @@ StmtNode *parseSwitchStmtNode(Token ***tokenp)
|
|||
goto parseSwitchStmtNodeAbort;
|
||||
}
|
||||
|
||||
/* Remove the question mark from the token stream */
|
||||
status = acceptToken(&tokens, TT_QUESTION);
|
||||
if (!status) {
|
||||
parser_error_expected_token(TT_QUESTION, tokens);
|
||||
goto parseSwitchStmtNodeAbort;
|
||||
}
|
||||
|
||||
/* The switch keyword must appear on its own line */
|
||||
status = acceptToken(&tokens, TT_NEWLINE);
|
||||
if (!status) {
|
||||
|
@ -3872,6 +3963,76 @@ parseAltArrayDefStmtNodeAbort: /* Exception handling */
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses tokens into a library import statement.
|
||||
*
|
||||
* \param [in] tokenp The position in a token list to start parsing at.
|
||||
*
|
||||
* \post \a tokenp will point to the next unparsed token.
|
||||
*
|
||||
* \return A pointer to a return statement.
|
||||
*
|
||||
* \retval NULL Unable to parse.
|
||||
*/
|
||||
StmtNode *parseImportStmtNode(Token ***tokenp)
|
||||
{
|
||||
IdentifierNode *value = NULL;
|
||||
ImportStmtNode *stmt = NULL;
|
||||
StmtNode *ret = NULL;
|
||||
int status;
|
||||
|
||||
/* Work from a copy of the token stream in case something goes wrong */
|
||||
Token **tokens = *tokenp;
|
||||
|
||||
#ifdef DEBUG
|
||||
debug("ST_IMPORT");
|
||||
#endif
|
||||
|
||||
/* Remove the library import keyword from the token stream */
|
||||
status = acceptToken(&tokens, TT_CANHAS);
|
||||
if (!status) {
|
||||
parser_error_expected_token(TT_CANHAS, tokens);
|
||||
goto parseImportStmtNodeAbort;
|
||||
}
|
||||
|
||||
/* Parse the library name */
|
||||
value = parseIdentifierNode(&tokens);
|
||||
if (!value) goto parseImportStmtNodeAbort;
|
||||
|
||||
/* Check for the question mark token (currently optional) */
|
||||
acceptToken(&tokens, TT_QUESTION);
|
||||
|
||||
/* The library import statement must reside on its own line */
|
||||
status = acceptToken(&tokens, TT_NEWLINE);
|
||||
if (!status) {
|
||||
parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens);
|
||||
goto parseImportStmtNodeAbort;
|
||||
}
|
||||
|
||||
/* Create the new ImportStmtNode structure */
|
||||
stmt = createImportStmtNode(value);
|
||||
if (!stmt) goto parseImportStmtNodeAbort;
|
||||
|
||||
/* Create the new StmtNode structure */
|
||||
ret = createStmtNode(ST_IMPORT, stmt);
|
||||
if (!ret) goto parseImportStmtNodeAbort;
|
||||
|
||||
/* Since we're successful, update the token stream */
|
||||
*tokenp = tokens;
|
||||
|
||||
return ret;
|
||||
|
||||
parseImportStmtNodeAbort: /* Exception handling */
|
||||
|
||||
/* Clean up any allocated structures */
|
||||
if (ret) deleteStmtNode(ret);
|
||||
else if (stmt) deleteImportStmtNode(stmt);
|
||||
else {
|
||||
if (value) deleteIdentifierNode(value);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses tokens into a statement.
|
||||
*
|
||||
|
@ -3990,6 +4151,10 @@ StmtNode *parseStmtNode(Token ***tokenp)
|
|||
else if (peekToken(&tokens, TT_OHAIIM)) {
|
||||
ret = parseAltArrayDefStmtNode(tokenp);
|
||||
}
|
||||
/* Library import statement */
|
||||
else if (peekToken(&tokens, TT_CANHAS)) {
|
||||
ret = parseImportStmtNode(tokenp);
|
||||
}
|
||||
/* Bare expression */
|
||||
else if ((expr = parseExprNode(&tokens))) {
|
||||
int status;
|
||||
|
|
41
parser.h
41
parser.h
|
@ -228,6 +228,8 @@ typedef enum {
|
|||
ST_FUNCDEF, /**< Function definition statement. */
|
||||
ST_EXPR, /**< Expression statement. */
|
||||
ST_ALTARRAYDEF, /**< Function definition statement. */
|
||||
ST_BINDING, /**< Binding to external library. */
|
||||
ST_IMPORT, /**< Library import statement. */
|
||||
} StmtType;
|
||||
|
||||
/**
|
||||
|
@ -364,6 +366,22 @@ typedef struct {
|
|||
IdentifierNode *parent; /**< An optional inherited array. */
|
||||
} AltArrayDefStmtNode;
|
||||
|
||||
/**
|
||||
* Stores a library import statement.
|
||||
*/
|
||||
typedef struct {
|
||||
IdentifierNode *name; /**< The name of the library to import. */
|
||||
} ImportStmtNode;
|
||||
|
||||
/**
|
||||
* Stores a binding to a native function.
|
||||
*/
|
||||
struct returnobject;
|
||||
struct scopeobject;
|
||||
typedef struct {
|
||||
struct returnobject *(*binding)(struct scopeobject *); /**< The function that implements the binding. */
|
||||
} BindingStmtNode;
|
||||
|
||||
/**
|
||||
* Stores the main code block of a program.
|
||||
*
|
||||
|
@ -716,6 +734,28 @@ AltArrayDefStmtNode *createAltArrayDefStmtNode(IdentifierNode *, BlockNode *, Id
|
|||
void deleteAltArrayDefStmtNode(AltArrayDefStmtNode *);
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* \name ImportStmtNode modifiers
|
||||
*
|
||||
* Functions for creating and deleting ImportStmtNodes.
|
||||
*/
|
||||
/**@{*/
|
||||
ImportStmtNode *createImportStmtNode(IdentifierNode *);
|
||||
void deleteImportStmtNode(ImportStmtNode *);
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* \name BindingStmtNode modifiers
|
||||
*
|
||||
* Functions for creating and deleting BindingStmtNodes.
|
||||
*/
|
||||
/**@{*/
|
||||
struct returnobject;
|
||||
struct scopeobject;
|
||||
BindingStmtNode *createBindingStmtNode(struct returnobject *(*)(struct scopeobject *));
|
||||
void deleteBindingStmtNode(BindingStmtNode *);
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* \name ExprNode modifiers
|
||||
*
|
||||
|
@ -801,6 +841,7 @@ StmtNode *parseLoopStmtNode(Token ***);
|
|||
StmtNode *parseDeallocationStmtNode(Token ***);
|
||||
StmtNode *parseFuncDefStmtNode(Token ***);
|
||||
StmtNode *parseAltArrayDefStmtNode(Token ***);
|
||||
StmtNode *parseImportStmtNode(Token ***);
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,12 +1,4 @@
|
|||
add_subdirectory(1-EmptyMainBlock)
|
||||
add_subdirectory(10-CommasSeparate)
|
||||
add_subdirectory(11-EllipsesJoinLF)
|
||||
add_subdirectory(12-EllipsesJoinCR)
|
||||
add_subdirectory(13-EllipsesJoinCRLF)
|
||||
add_subdirectory(14-NoNewlineAfterJoinLF)
|
||||
add_subdirectory(15-NoNewlineAfterJoinCR)
|
||||
add_subdirectory(16-NoNewlineAfterJoinCRLF)
|
||||
add_subdirectory(17-Includes)
|
||||
add_subdirectory(2-MustBeginWithHAI)
|
||||
add_subdirectory(3-MustIncludeVersion)
|
||||
add_subdirectory(4-MustEndWithKTHXBYE)
|
||||
|
@ -15,3 +7,11 @@ add_subdirectory(6-WhitespaceBetweenTokens)
|
|||
add_subdirectory(7-NewlineLF)
|
||||
add_subdirectory(8-NewlineCR)
|
||||
add_subdirectory(9-NewlineCRLF)
|
||||
add_subdirectory(10-CommasSeparate)
|
||||
add_subdirectory(11-EllipsesJoinLF)
|
||||
add_subdirectory(12-EllipsesJoinCR)
|
||||
add_subdirectory(13-EllipsesJoinCRLF)
|
||||
add_subdirectory(14-NoNewlineAfterJoinLF)
|
||||
add_subdirectory(15-NoNewlineAfterJoinCR)
|
||||
add_subdirectory(16-NoNewlineAfterJoinCRLF)
|
||||
add_subdirectory(17-Includes)
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
add_subdirectory(1-EmptyArray)
|
||||
add_subdirectory(10-CallingObjectInitialization)
|
||||
add_subdirectory(11-AlternateSyntax)
|
||||
add_subdirectory(12-Inheritance)
|
||||
add_subdirectory(2-SlotCreation)
|
||||
add_subdirectory(3-SlotInitialization)
|
||||
add_subdirectory(4-SlotAssignment)
|
||||
|
@ -10,3 +7,6 @@ add_subdirectory(6-FunctionDeclaration)
|
|||
add_subdirectory(7-CallingObjectReference)
|
||||
add_subdirectory(8-CallingObjectAssignment)
|
||||
add_subdirectory(9-CallingObjectDeclaration)
|
||||
add_subdirectory(10-CallingObjectInitialization)
|
||||
add_subdirectory(11-AlternateSyntax)
|
||||
add_subdirectory(12-Inheritance)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
add_subdirectory(1-SeparateStartEndLines)
|
||||
add_subdirectory(10-AfterKTHXBYE)
|
||||
add_subdirectory(2-SeparateStartLineOnly)
|
||||
add_subdirectory(3-SeparateEndLineOnly)
|
||||
add_subdirectory(4-MustStartOnSeparateLine)
|
||||
|
@ -8,3 +7,4 @@ add_subdirectory(6-BeginAfterLineSeparator)
|
|||
add_subdirectory(7-EndBeforeLineSeparator)
|
||||
add_subdirectory(8-IgnoreEmbeddedBTW)
|
||||
add_subdirectory(9-BeforeHAI)
|
||||
add_subdirectory(10-AfterKTHXBYE)
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
add_subdirectory(1-Output)
|
||||
add_subdirectory(2-Initialization)
|
||||
add_subdirectory(3-Assignment)
|
||||
add_subdirectory(4-TypeInitialization)
|
||||
add_subdirectory(5-Deallocation)
|
||||
add_subdirectory(6-Functions)
|
|
@ -7,3 +7,4 @@ add_subdirectory(6-Assignment)
|
|||
add_subdirectory(7-AssignmentSameVariable)
|
||||
add_subdirectory(8-TypeInitialization)
|
||||
add_subdirectory(9-Deallocation)
|
||||
add_subdirectory(10-Indirect)
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
add_subdirectory(1-Intergers)
|
||||
add_subdirectory(10-ArityCheck)
|
||||
add_subdirectory(11-OptionalAN)
|
||||
add_subdirectory(2-FloatInteger)
|
||||
add_subdirectory(3-IntegerFloat)
|
||||
add_subdirectory(4-Floats)
|
||||
|
@ -9,3 +7,5 @@ add_subdirectory(6-FloatIntegerStrings)
|
|||
add_subdirectory(7-IntegerFloatStrings)
|
||||
add_subdirectory(8-FloatStrings)
|
||||
add_subdirectory(9-Nested)
|
||||
add_subdirectory(10-ArityCheck)
|
||||
add_subdirectory(11-OptionalAN)
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
add_subdirectory(1-Addition)
|
||||
add_subdirectory(2-Subtraction)
|
||||
add_subdirectory(3-Multiplication)
|
||||
add_subdirectory(4-Division)
|
||||
add_subdirectory(5-Modulo)
|
||||
add_subdirectory(6-Maximum)
|
||||
add_subdirectory(7-Minimum)
|
||||
add_subdirectory(8-LogicalANDBinary)
|
||||
add_subdirectory(9-LogicalORBinary)
|
||||
add_subdirectory(10-LogicalXORBinary)
|
||||
add_subdirectory(11-LogicalNOTUnary)
|
||||
add_subdirectory(12-LogicalANDNary)
|
||||
|
@ -8,11 +16,3 @@ add_subdirectory(15-Inequality)
|
|||
add_subdirectory(16-Concatenation)
|
||||
add_subdirectory(17-ExplicitCast)
|
||||
add_subdirectory(18-ExplicitRecast)
|
||||
add_subdirectory(2-Subtraction)
|
||||
add_subdirectory(3-Multiplication)
|
||||
add_subdirectory(4-Division)
|
||||
add_subdirectory(5-Modulo)
|
||||
add_subdirectory(6-Maximum)
|
||||
add_subdirectory(7-Minimum)
|
||||
add_subdirectory(8-LogicalANDBinary)
|
||||
add_subdirectory(9-LogicalORBinary)
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
add_subdirectory(1-VoidWithSideEffects)
|
||||
add_subdirectory(10-TooFewArguments)
|
||||
add_subdirectory(11-EmptyBody)
|
||||
add_subdirectory(2-ReturnValue)
|
||||
add_subdirectory(3-VoidReturnValue)
|
||||
add_subdirectory(4-NilReturnValue)
|
||||
|
@ -9,3 +7,5 @@ add_subdirectory(6-DoubleRecursion)
|
|||
add_subdirectory(7-ExpressionArguments)
|
||||
add_subdirectory(8-VoidMustHaveNoArguments)
|
||||
add_subdirectory(9-TooManyArguments)
|
||||
add_subdirectory(10-TooFewArguments)
|
||||
add_subdirectory(11-EmptyBody)
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
add_subdirectory(0-Benchmarks)
|
||||
add_subdirectory(1-Structure)
|
||||
add_subdirectory(10-Loops)
|
||||
add_subdirectory(11-Unicode)
|
||||
add_subdirectory(12-Arrays)
|
||||
add_subdirectory(2-Comments)
|
||||
add_subdirectory(3-Types)
|
||||
add_subdirectory(4-Output)
|
||||
|
@ -11,3 +8,6 @@ add_subdirectory(6-Variables)
|
|||
add_subdirectory(7-Operators)
|
||||
add_subdirectory(8-Conditionals)
|
||||
add_subdirectory(9-Functions)
|
||||
add_subdirectory(10-Loops)
|
||||
add_subdirectory(11-Unicode)
|
||||
add_subdirectory(12-Arrays)
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
INCLUDE(AddLolTest)
|
||||
ADD_LOL_TEST(1-fopen OUTPUT test.out)
|
|
@ -0,0 +1,7 @@
|
|||
THE fog comes
|
||||
on little cat feet.
|
||||
|
||||
It sits looking
|
||||
over harbor and city
|
||||
on silent haunches
|
||||
and then moves on.
|
|
@ -0,0 +1,10 @@
|
|||
HAI 1.4
|
||||
CAN HAS STDIO?
|
||||
I HAS A file
|
||||
file R I IZ STDIO'Z FOPENIN YR "read.dat" AN YR "r" MKAY
|
||||
file R I IZ STDIO'Z FOPENIN YR "write.dat" AN YR "w" MKAY
|
||||
file R I IZ STDIO'Z FOPENIN YR "write.dat" AN YR "a" MKAY
|
||||
file R I IZ STDIO'Z FOPENIN YR "write.dat" AN YR "r+" MKAY
|
||||
file R I IZ STDIO'Z FOPENIN YR "write.dat" AN YR "w+" MKAY
|
||||
file R I IZ STDIO'Z FOPENIN YR "write.dat" AN YR "a+" MKAY
|
||||
KTHXBYE
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(1-fopen)
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(1-stdio)
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(13-Bindings)
|
|
@ -1 +1,2 @@
|
|||
add_subdirectory(1.3-Tests)
|
||||
add_subdirectory(1.4-Tests)
|
||||
|
|
|
@ -319,15 +319,6 @@ Token **tokenizeLexemes(LexemeList *list)
|
|||
token = createToken(TT_BOOLEAN, "WIN", fname, line);
|
||||
token->data.i = 1;
|
||||
}
|
||||
/* CAN HAS STDIO? */
|
||||
else if (n < list->num - 2
|
||||
&& !strcmp(lexeme->image, "CAN")
|
||||
&& !strcmp(list->lexemes[n + 1]->image, "HAS")
|
||||
&& !strcmp(list->lexemes[n + 2]->image, "STDIO?")) {
|
||||
n += 2;
|
||||
/* Just for fun; not actually in spec */
|
||||
continue;
|
||||
}
|
||||
/* Newline */
|
||||
/* Note that the spec is unclear as to whether a command *must*
|
||||
* follow a comma. For now, we let commas end a line. */
|
||||
|
|
|
@ -104,6 +104,8 @@ typedef enum {
|
|||
TT_OHAIIM, /**< Alternate array declaration. */
|
||||
TT_IMLIEK, /**< Alternate inherited object declaration. */
|
||||
TT_KTHX, /**< End of alternate array declaration. */
|
||||
TT_CANHAS, /**< Library import declaration. */
|
||||
TT_QUESTION, /**< End of library import declaration. */
|
||||
|
||||
TT_ENDOFTOKENS /**< Sentinel end of this enum -- don't move it! */
|
||||
} TokenType;
|
||||
|
@ -156,12 +158,12 @@ static const char *keywords[] = {
|
|||
"SMOOSH", /* TT_SMOOSH */
|
||||
"!", /* TT_BANG */
|
||||
"GIMMEH", /* TT_GIMMEH */
|
||||
"O RLY?", /* TT_ORLY */
|
||||
"O RLY", /* TT_ORLY */
|
||||
"YA RLY", /* TT_YARLY */
|
||||
"MEBBE", /* TT_MEBBE */
|
||||
"NO WAI", /* TT_NOWAI */
|
||||
"OIC", /* TT_OIC */
|
||||
"WTF?", /* TT_WTF */
|
||||
"WTF", /* TT_WTF */
|
||||
"OMG", /* TT_OMG */
|
||||
"OMGWTF", /* TT_OMGWTF */
|
||||
"GTFO", /* TT_GTFO */
|
||||
|
@ -181,6 +183,8 @@ static const char *keywords[] = {
|
|||
"O HAI IM", /* TT_OHAIIM */
|
||||
"IM LIEK", /* TT_IMLIEK */
|
||||
"KTHX", /* TT_KTHX */
|
||||
"CAN HAS", /* TT_CANHAS */
|
||||
"?", /* TT_QUESTION */
|
||||
"" /* TT_ENDOFTOKENS */
|
||||
};
|
||||
|
||||
|
|
|
@ -19815,6 +19815,7 @@ static const char *names[] = {
|
|||
"TRUMPET",
|
||||
"TUGRIK SIGN",
|
||||
"TULIP",
|
||||
"TURKISH LIRA SIGN",
|
||||
"TURNED AMPERSAND",
|
||||
"TURNED ANGLE",
|
||||
"TURNED BLACK SHOGI PIECE",
|
||||
|
@ -41559,6 +41560,7 @@ static const long codepoints[] = {
|
|||
0x1F3BA,
|
||||
0x20AE,
|
||||
0x1F337,
|
||||
0x20BA,
|
||||
0x214B,
|
||||
0x29A2,
|
||||
0x26CA,
|
||||
|
@ -43488,7 +43490,7 @@ static const long codepoints[] = {
|
|||
0x200B
|
||||
};
|
||||
|
||||
#define NUM_UNICODE 21741
|
||||
#define NUM_UNICODE 21742
|
||||
|
||||
/**
|
||||
* Performs a binary search on an array of strings.
|
||||
|
|
Loading…
Reference in New Issue