Initial commit
This commit is contained in:
commit
f7122b9513
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
bin/*
|
||||||
|
test/*
|
||||||
|
test
|
||||||
|
bin
|
20
LICENSE.txt
Normal file
20
LICENSE.txt
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
Copyright (c) 2015 Benjamin Moir
|
||||||
|
Copyright (c) 2015 Marrub <marrub@greyserv.net>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
8
Makefile
Normal file
8
Makefile
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# sorry this makefile doesn't include anything cross-platform
|
||||||
|
# was hurriedly made to test it
|
||||||
|
|
||||||
|
all:
|
||||||
|
mkdir -p bin
|
||||||
|
mingw32-gcc --std=c99 -g -ggdb -c -o bin/lt.o lt.c
|
||||||
|
mingw32-gcc -shared -g -ggdb -o bin/LoveToken.dll bin/lt.o -Wl,--out-implib,bin/libLoveToken.a
|
||||||
|
# cp bin/LoveToken.dll test/LoveToken.dll
|
488
lt.c
Normal file
488
lt.c
Normal file
|
@ -0,0 +1,488 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2015 Benjamin Moir
|
||||||
|
Copyright (c) 2015 Marrub <marrub@greyserv.net>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "lt.h"
|
||||||
|
|
||||||
|
FILE *LT_ParseFile;
|
||||||
|
bool LT_AssertError = false;
|
||||||
|
LT_GarbageList *gbHead, *gbRover;
|
||||||
|
|
||||||
|
static bool escapeChars = true;
|
||||||
|
|
||||||
|
static char *tokenTypes[] = {
|
||||||
|
// [marrub] So, this was an interesting bug. This was completely misordered from the enum.
|
||||||
|
// As can be guessed, this caused many issues. Seriously, all of them.
|
||||||
|
"TOK_Colon", "TOK_Comma", "TOK_Div", "TOK_Mod", "TOK_Mul", "TOK_Query",
|
||||||
|
"TOK_BraceO", "TOK_BraceC", "TOK_BrackO", "TOK_BrackC", "TOK_ParenO", "TOK_ParenC",
|
||||||
|
"TOK_LnEnd", "TOK_Add2", "TOK_Add", "TOK_And2", "TOK_And", "TOK_CmpGE",
|
||||||
|
"TOK_ShR", "TOK_CmpGT", "TOK_CmpLE", "TOK_ShL", "TOK_CmpNE", "TOK_CmpLT",
|
||||||
|
"TOK_CmpEQ", "TOK_Equal", "TOK_Not", "TOK_OrI2", "TOK_OrI", "TOK_OrX2",
|
||||||
|
"TOK_OrX", "TOK_Sub2", "TOK_Sub", "TOK_String", "TOK_Charac", "TOK_Number",
|
||||||
|
"TOK_Identi", "TOK_EOF", "TOK_ChrSeq"
|
||||||
|
};
|
||||||
|
|
||||||
|
void LT_Init(LT_InitInfo initInfo)
|
||||||
|
{
|
||||||
|
escapeChars = initInfo.escapeChars;
|
||||||
|
|
||||||
|
gbHead = malloc(sizeof(LT_GarbageList));
|
||||||
|
gbHead->next = NULL;
|
||||||
|
gbHead->ptr = NULL;
|
||||||
|
|
||||||
|
gbRover = gbHead;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LT_Quit()
|
||||||
|
{
|
||||||
|
gbRover = gbHead;
|
||||||
|
|
||||||
|
while(gbRover != NULL)
|
||||||
|
{
|
||||||
|
LT_GarbageList *next = gbRover->next;
|
||||||
|
|
||||||
|
if(gbRover->ptr != NULL)
|
||||||
|
{
|
||||||
|
free(gbRover->ptr);
|
||||||
|
gbRover->ptr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(gbRover);
|
||||||
|
|
||||||
|
gbRover = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
gbRover = NULL;
|
||||||
|
gbHead = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LT_Assert(bool assertion, const char *str)
|
||||||
|
{
|
||||||
|
if(assertion)
|
||||||
|
{
|
||||||
|
LT_AssertError = true;
|
||||||
|
fprintf(stderr, "LT_Assert: %s", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
return assertion;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LT_OpenFile(const char *filePath)
|
||||||
|
{
|
||||||
|
LT_ParseFile = fopen(filePath, "r");
|
||||||
|
|
||||||
|
if(LT_ParseFile == NULL)
|
||||||
|
{
|
||||||
|
perror("LT_OpenFile");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LT_CloseFile()
|
||||||
|
{
|
||||||
|
if(LT_ParseFile != NULL)
|
||||||
|
{
|
||||||
|
fclose(LT_ParseFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *LT_ReadNumber()
|
||||||
|
{
|
||||||
|
size_t i = 0, str_blocks = 1;
|
||||||
|
char c, *str = malloc(TOKEN_STR_BLOCK_LENGTH);
|
||||||
|
|
||||||
|
while(!feof(LT_ParseFile))
|
||||||
|
{
|
||||||
|
fread(&c, 1, 1, LT_ParseFile);
|
||||||
|
|
||||||
|
if(!isalnum(c))
|
||||||
|
{
|
||||||
|
fseek(LT_ParseFile, -1, SEEK_CUR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(i > TOKEN_STR_BLOCK_LENGTH)
|
||||||
|
{
|
||||||
|
realloc(str, TOKEN_STR_BLOCK_LENGTH * str_blocks++);
|
||||||
|
}
|
||||||
|
|
||||||
|
str[i++] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
str[i++] = '\0';
|
||||||
|
|
||||||
|
gbRover->next = malloc(sizeof(LT_GarbageList));
|
||||||
|
gbRover = gbRover->next;
|
||||||
|
gbRover->ptr = realloc(str, i);
|
||||||
|
gbRover->next = NULL;
|
||||||
|
|
||||||
|
return gbRover->ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *LT_ReadString(char term)
|
||||||
|
{
|
||||||
|
size_t i = 0, str_blocks = 1;
|
||||||
|
char c, *str = malloc(TOKEN_STR_BLOCK_LENGTH);
|
||||||
|
static char *emptyString = "";
|
||||||
|
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
fread(&c, 1, 1, LT_ParseFile);
|
||||||
|
|
||||||
|
if(c == term)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(LT_Assert(feof(LT_ParseFile) || c == '\n', "unterminated string literal"))
|
||||||
|
{
|
||||||
|
return emptyString;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(c == '\\' && escapeChars)
|
||||||
|
{
|
||||||
|
fread(&c, 1, 1, LT_ParseFile);
|
||||||
|
|
||||||
|
if(LT_Assert(feof(LT_ParseFile) || c == '\n', "unterminated string literal"))
|
||||||
|
{
|
||||||
|
str[i] = '\0';
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(i > TOKEN_STR_BLOCK_LENGTH)
|
||||||
|
{
|
||||||
|
realloc(str, TOKEN_STR_BLOCK_LENGTH * str_blocks++);
|
||||||
|
}
|
||||||
|
|
||||||
|
str = LT_Escaper(str, i++, c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(i > TOKEN_STR_BLOCK_LENGTH)
|
||||||
|
{
|
||||||
|
realloc(str, TOKEN_STR_BLOCK_LENGTH * str_blocks++);
|
||||||
|
}
|
||||||
|
|
||||||
|
str[i++] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
str[i++] = '\0';
|
||||||
|
|
||||||
|
gbRover->next = malloc(sizeof(LT_GarbageList));
|
||||||
|
gbRover = gbRover->next;
|
||||||
|
gbRover->ptr = realloc(str, i);
|
||||||
|
gbRover->next = NULL;
|
||||||
|
|
||||||
|
return gbRover->ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *LT_Escaper(char *str, size_t pos, char escape)
|
||||||
|
{
|
||||||
|
switch(escape)
|
||||||
|
{
|
||||||
|
case '\\': case '\'': case '"': str[pos] = escape; break;
|
||||||
|
case 'C': str[pos] = '\x1C'; break;
|
||||||
|
case 'a': str[pos] = '\a'; break;
|
||||||
|
case 'b': str[pos] = '\b'; break;
|
||||||
|
case 'f': str[pos] = '\f'; break;
|
||||||
|
case 'n': str[pos] = '\n'; break;
|
||||||
|
case 'r': str[pos] = '\r'; break;
|
||||||
|
case 't': str[pos] = '\t'; break;
|
||||||
|
case 'v': str[pos] = '\v'; break;
|
||||||
|
case 'x': // [marrub] THIS ONE IS FUN
|
||||||
|
for(unsigned int i = 0;;)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
fread(&c, 1, 1, LT_ParseFile);
|
||||||
|
|
||||||
|
switch(c)
|
||||||
|
{
|
||||||
|
case '0': i = i * 16 + 0x0; break;
|
||||||
|
case '1': i = i * 16 + 0x1; break;
|
||||||
|
case '2': i = i * 16 + 0x2; break;
|
||||||
|
case '3': i = i * 16 + 0x3; break;
|
||||||
|
case '4': i = i * 16 + 0x4; break;
|
||||||
|
case '5': i = i * 16 + 0x5; break;
|
||||||
|
case '6': i = i * 16 + 0x6; break;
|
||||||
|
case '7': i = i * 16 + 0x7; break;
|
||||||
|
case '8': i = i * 16 + 0x8; break;
|
||||||
|
case '9': i = i * 16 + 0x9; break;
|
||||||
|
case 'a': case 'A': i = i * 16 + 0xA; break;
|
||||||
|
case 'b': case 'B': i = i * 16 + 0xB; break;
|
||||||
|
case 'c': case 'C': i = i * 16 + 0xC; break;
|
||||||
|
case 'd': case 'D': i = i * 16 + 0xD; break;
|
||||||
|
case 'e': case 'E': i = i * 16 + 0xE; break;
|
||||||
|
case 'f': case 'F': i = i * 16 + 0xF; break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fseek(LT_ParseFile, -1, SEEK_CUR);
|
||||||
|
str[pos] = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '0': case '1': case '2': case '3':
|
||||||
|
case '4': case '5': case '6': case '7':
|
||||||
|
{
|
||||||
|
char c = escape;
|
||||||
|
unsigned int i = 0;
|
||||||
|
|
||||||
|
for(unsigned int n = 2; n != 0; n--)
|
||||||
|
{
|
||||||
|
switch(c)
|
||||||
|
{
|
||||||
|
case '0': i = i * 8 + 00; break;
|
||||||
|
case '1': i = i * 8 + 01; break;
|
||||||
|
case '2': i = i * 8 + 02; break;
|
||||||
|
case '3': i = i * 8 + 03; break;
|
||||||
|
case '4': i = i * 8 + 04; break;
|
||||||
|
case '5': i = i * 8 + 05; break;
|
||||||
|
case '6': i = i * 8 + 06; break;
|
||||||
|
case '7': i = i * 8 + 07; break;
|
||||||
|
default:
|
||||||
|
fseek(LT_ParseFile, -1, SEEK_CUR);
|
||||||
|
str[pos] = i;
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
fread(&c, 1, 1, LT_ParseFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
str[pos] = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default: LT_Assert(true, "unknown escape character"); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
LT_Token LT_GetToken()
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
LT_Token tk = { 0 };
|
||||||
|
|
||||||
|
fread(&c, 1, 1, LT_ParseFile);
|
||||||
|
|
||||||
|
if(feof(LT_ParseFile))
|
||||||
|
{
|
||||||
|
tk.token = tokenTypes[TOK_EOF];
|
||||||
|
tk.string = NULL;
|
||||||
|
tk.pos = ftell(LT_ParseFile);
|
||||||
|
return tk;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(isspace(c) && c != '\n')
|
||||||
|
{
|
||||||
|
fread(&c, 1, 1, LT_ParseFile);
|
||||||
|
|
||||||
|
if(feof(LT_ParseFile)) // [marrub] This could have caused issues if there was whitespace before EOF.
|
||||||
|
{
|
||||||
|
tk.token = tokenTypes[TOK_EOF];
|
||||||
|
tk.string = NULL;
|
||||||
|
tk.pos = ftell(LT_ParseFile);
|
||||||
|
return tk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tk.pos = ftell(LT_ParseFile);
|
||||||
|
|
||||||
|
switch(c)
|
||||||
|
{
|
||||||
|
case ':': tk.token = tokenTypes[TOK_Colon]; return tk;
|
||||||
|
case ',': tk.token = tokenTypes[TOK_Comma]; return tk;
|
||||||
|
case '/': tk.token = tokenTypes[TOK_Div]; return tk;
|
||||||
|
case '%': tk.token = tokenTypes[TOK_Mod]; return tk;
|
||||||
|
case '*': tk.token = tokenTypes[TOK_Mul]; return tk;
|
||||||
|
case '?': tk.token = tokenTypes[TOK_Query]; return tk;
|
||||||
|
case '{': tk.token = tokenTypes[TOK_BraceO]; return tk;
|
||||||
|
case '}': tk.token = tokenTypes[TOK_BraceC]; return tk;
|
||||||
|
case '[': tk.token = tokenTypes[TOK_BrackO]; return tk;
|
||||||
|
case ']': tk.token = tokenTypes[TOK_BrackC]; return tk;
|
||||||
|
case '(': tk.token = tokenTypes[TOK_ParenO]; return tk;
|
||||||
|
case ')': tk.token = tokenTypes[TOK_ParenC]; return tk;
|
||||||
|
case '\n': tk.token = tokenTypes[TOK_LnEnd]; return tk;
|
||||||
|
|
||||||
|
// [marrub] Sorry, I wouldn't normally do a quick and dirty hack like this,
|
||||||
|
// but sometimes I really do care about my sanity. And wrists.
|
||||||
|
#define DoubleTokDef(ch, t1, t2) \
|
||||||
|
case ch: \
|
||||||
|
fread(&c, 1, 1, LT_ParseFile); \
|
||||||
|
\
|
||||||
|
if(c == ch) \
|
||||||
|
{ \
|
||||||
|
tk.token = tokenTypes[t2]; \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
tk.token = tokenTypes[t1]; \
|
||||||
|
fseek(LT_ParseFile, -1, SEEK_CUR); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
return tk;
|
||||||
|
|
||||||
|
DoubleTokDef('+', TOK_Add, TOK_Add2);
|
||||||
|
DoubleTokDef('-', TOK_Sub, TOK_Sub2);
|
||||||
|
DoubleTokDef('&', TOK_And, TOK_And2);
|
||||||
|
DoubleTokDef('=', TOK_Equal, TOK_CmpEQ);
|
||||||
|
DoubleTokDef('^', TOK_OrX, TOK_OrX2);
|
||||||
|
DoubleTokDef('|', TOK_OrI, TOK_OrI2);
|
||||||
|
|
||||||
|
#undef DoubleTokDef
|
||||||
|
|
||||||
|
// [marrub] Special god damn snowflakes
|
||||||
|
case '>':
|
||||||
|
fread(&c, 1, 1, LT_ParseFile);
|
||||||
|
|
||||||
|
if(c == '=')
|
||||||
|
{
|
||||||
|
tk.token = tokenTypes[TOK_CmpGE];
|
||||||
|
}
|
||||||
|
else if(c == '>')
|
||||||
|
{
|
||||||
|
tk.token = tokenTypes[TOK_ShR];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tk.token = tokenTypes[TOK_CmpGT];
|
||||||
|
fseek(LT_ParseFile, -1, SEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tk;
|
||||||
|
case '<':
|
||||||
|
fread(&c, 1, 1, LT_ParseFile);
|
||||||
|
|
||||||
|
if(c == '=')
|
||||||
|
{
|
||||||
|
tk.token = tokenTypes[TOK_CmpLE];
|
||||||
|
}
|
||||||
|
else if(c == '<')
|
||||||
|
{
|
||||||
|
tk.token = tokenTypes[TOK_ShL];
|
||||||
|
}
|
||||||
|
else if(c == '>')
|
||||||
|
{
|
||||||
|
tk.token = tokenTypes[TOK_CmpNE];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tk.token = tokenTypes[TOK_CmpLT];
|
||||||
|
fseek(LT_ParseFile, -1, SEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tk;
|
||||||
|
case '!':
|
||||||
|
fread(&c, 1, 1, LT_ParseFile);
|
||||||
|
|
||||||
|
if(c == '=')
|
||||||
|
{
|
||||||
|
tk.token = tokenTypes[TOK_CmpNE];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tk.token = tokenTypes[TOK_Not];
|
||||||
|
fseek(LT_ParseFile, -1, SEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tk;
|
||||||
|
case '~':
|
||||||
|
fread(&c, 1, 1, LT_ParseFile);
|
||||||
|
|
||||||
|
if(c == '=')
|
||||||
|
{
|
||||||
|
tk.token = tokenTypes[TOK_CmpNE];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fseek(LT_ParseFile, -1, SEEK_CUR);
|
||||||
|
LT_Assert(true, "syntax error"); // [marrub] Yet more error checking that was forgotten before.
|
||||||
|
}
|
||||||
|
|
||||||
|
return tk;
|
||||||
|
case '"': case '\'':
|
||||||
|
tk.string = LT_ReadString(c);
|
||||||
|
|
||||||
|
if(c == '"')
|
||||||
|
{
|
||||||
|
tk.token = tokenTypes[TOK_String];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tk.token = tokenTypes[TOK_Charac];
|
||||||
|
}
|
||||||
|
|
||||||
|
return tk;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isdigit(c))
|
||||||
|
{
|
||||||
|
fseek(LT_ParseFile, -1, SEEK_CUR);
|
||||||
|
|
||||||
|
tk.string = LT_ReadNumber();
|
||||||
|
tk.token = tokenTypes[TOK_Number];
|
||||||
|
return tk;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isalpha(c) || c == '_')
|
||||||
|
{
|
||||||
|
size_t i = 0, str_blocks = 1;
|
||||||
|
char *str = malloc(TOKEN_STR_BLOCK_LENGTH);
|
||||||
|
|
||||||
|
while(!(feof(LT_ParseFile)) && (isalnum(c) || c == '_'))
|
||||||
|
{
|
||||||
|
if(i > TOKEN_STR_BLOCK_LENGTH)
|
||||||
|
{
|
||||||
|
realloc(str, TOKEN_STR_BLOCK_LENGTH * str_blocks++);
|
||||||
|
}
|
||||||
|
|
||||||
|
str[i++] = c;
|
||||||
|
fread(&c, 1, 1, LT_ParseFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
str[i++] = '\0'; // [marrub] Completely forgot this line earlier. Really screwed up everything.
|
||||||
|
|
||||||
|
gbRover->next = malloc(sizeof(LT_GarbageList));
|
||||||
|
gbRover = gbRover->next;
|
||||||
|
gbRover->ptr = realloc(str, i);
|
||||||
|
gbRover->next = NULL;
|
||||||
|
|
||||||
|
fseek(LT_ParseFile, -1, SEEK_CUR);
|
||||||
|
|
||||||
|
tk.string = gbRover->ptr;
|
||||||
|
tk.token = tokenTypes[TOK_Identi];
|
||||||
|
return tk;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tk;
|
||||||
|
}
|
||||||
|
|
117
lt.h
Normal file
117
lt.h
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2015 Benjamin Moir
|
||||||
|
Copyright (c) 2015 Marrub <marrub@greyserv.net>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LOVETOKEN_LT_H
|
||||||
|
#define LOVETOKEN_LT_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define TOKEN_STR_BLOCK_LENGTH 512
|
||||||
|
|
||||||
|
// [marrub] When using in FFI, remove this from the definitions
|
||||||
|
// Also redefine this for cross-platform.
|
||||||
|
#define LT_EXPORT __declspec(dllexport)
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
bool escapeChars;
|
||||||
|
} LT_InitInfo;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char *token;
|
||||||
|
char *string;
|
||||||
|
int pos;
|
||||||
|
} LT_Token;
|
||||||
|
|
||||||
|
extern bool LT_EXPORT LT_AssertError;
|
||||||
|
|
||||||
|
void LT_EXPORT LT_Init(LT_InitInfo initInfo);
|
||||||
|
void LT_EXPORT LT_Quit();
|
||||||
|
bool LT_EXPORT LT_Assert(bool assertion, const char *str);
|
||||||
|
|
||||||
|
bool LT_EXPORT LT_OpenFile(const char *filePath);
|
||||||
|
void LT_EXPORT LT_CloseFile();
|
||||||
|
|
||||||
|
char *LT_EXPORT LT_ReadNumber();
|
||||||
|
char *LT_EXPORT LT_ReadString(char term);
|
||||||
|
char *LT_EXPORT LT_Escaper(char *str, size_t pos, char escape);
|
||||||
|
LT_Token LT_EXPORT LT_GetToken();
|
||||||
|
|
||||||
|
// [marrub] Don't include stuff below here into the FFI definitions
|
||||||
|
|
||||||
|
typedef struct LT_GarbageList_s
|
||||||
|
{
|
||||||
|
struct LT_GarbageList_s *next;
|
||||||
|
void *ptr;
|
||||||
|
} LT_GarbageList;
|
||||||
|
|
||||||
|
extern FILE *LT_ParseFile;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
TOK_Colon,
|
||||||
|
TOK_Comma,
|
||||||
|
TOK_Div,
|
||||||
|
TOK_Mod,
|
||||||
|
TOK_Mul,
|
||||||
|
TOK_Query,
|
||||||
|
TOK_BraceO,
|
||||||
|
TOK_BraceC,
|
||||||
|
TOK_BrackO,
|
||||||
|
TOK_BrackC,
|
||||||
|
TOK_ParenO,
|
||||||
|
TOK_ParenC,
|
||||||
|
TOK_LnEnd,
|
||||||
|
TOK_Add2,
|
||||||
|
TOK_Add,
|
||||||
|
TOK_And2,
|
||||||
|
TOK_And,
|
||||||
|
TOK_CmpGE,
|
||||||
|
TOK_ShR,
|
||||||
|
TOK_CmpGT,
|
||||||
|
TOK_CmpLE,
|
||||||
|
TOK_ShL,
|
||||||
|
TOK_CmpNE,
|
||||||
|
TOK_CmpLT,
|
||||||
|
TOK_CmpEQ,
|
||||||
|
TOK_Equal,
|
||||||
|
TOK_Not,
|
||||||
|
TOK_OrI2,
|
||||||
|
TOK_OrI,
|
||||||
|
TOK_OrX2,
|
||||||
|
TOK_OrX,
|
||||||
|
TOK_Sub2,
|
||||||
|
TOK_Sub,
|
||||||
|
TOK_String,
|
||||||
|
TOK_Charac,
|
||||||
|
TOK_Number,
|
||||||
|
TOK_Identi,
|
||||||
|
TOK_EOF,
|
||||||
|
TOK_ChrSeq
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
96
parser.lua
Normal file
96
parser.lua
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
--[[
|
||||||
|
|
||||||
|
Copyright (c) 2015 Benjamin Moir
|
||||||
|
Copyright (c) 2015 Marrub <marrub@greyserv.net>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local ffi = require("ffi")
|
||||||
|
local parser = {}
|
||||||
|
|
||||||
|
local loveToken = ffi.load("LoveToken")
|
||||||
|
ffi.cdef([[
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
bool escapeChars;
|
||||||
|
} LT_InitInfo;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char *token;
|
||||||
|
char *string;
|
||||||
|
int pos;
|
||||||
|
} LT_Token;
|
||||||
|
|
||||||
|
extern bool LT_AssertError;
|
||||||
|
|
||||||
|
void LT_Init(LT_InitInfo initInfo);
|
||||||
|
void LT_Quit();
|
||||||
|
bool LT_Assert(bool assertion, const char *str);
|
||||||
|
|
||||||
|
bool LT_OpenFile(const char *filePath);
|
||||||
|
void LT_CloseFile();
|
||||||
|
|
||||||
|
char *LT_ReadNumber();
|
||||||
|
char *LT_ReadString(char term);
|
||||||
|
char *LT_Escaper(char *str, size_t pos, char escape);
|
||||||
|
LT_Token LT_GetToken();
|
||||||
|
]])
|
||||||
|
|
||||||
|
function parser:init(initInfo, filePath)
|
||||||
|
loveToken.LT_Init(initInfo)
|
||||||
|
loveToken.LT_OpenFile(filePath)
|
||||||
|
end
|
||||||
|
|
||||||
|
function parser:assert(assertion, str)
|
||||||
|
return loveToken.LT_Assert(assertion, str)
|
||||||
|
end
|
||||||
|
|
||||||
|
function parser:openFile(filePath)
|
||||||
|
return loveToken.LT_OpenFile(filePath)
|
||||||
|
end
|
||||||
|
|
||||||
|
function parser:closeFile()
|
||||||
|
loveToken.LT_CloseFile()
|
||||||
|
end
|
||||||
|
|
||||||
|
function parser:quit()
|
||||||
|
loveToken.LT_CloseFile()
|
||||||
|
loveToken.LT_Quit()
|
||||||
|
end
|
||||||
|
|
||||||
|
function parser:readNumber()
|
||||||
|
return ffi.string(loveToken.LT_ReadNumber())
|
||||||
|
end
|
||||||
|
|
||||||
|
function parser:readString(term)
|
||||||
|
return ffi.string(loveToken.LT_ReadString(term))
|
||||||
|
end
|
||||||
|
|
||||||
|
function parser:escaper(str, pos, escape)
|
||||||
|
return ffi.string(loveToken.LT_Escaper(str, pos, escape))
|
||||||
|
end
|
||||||
|
|
||||||
|
function parser:getToken()
|
||||||
|
return loveToken.LT_GetToken()
|
||||||
|
end
|
||||||
|
|
||||||
|
return parser
|
Reference in New Issue
Block a user