start implimenting a parser
This commit is contained in:
@@ -1,2 +1,3 @@
|
|||||||
# Chloride
|
# Chloride
|
||||||
|
|
||||||
An Argon interpreter written in C
|
An Argon interpreter written in C
|
||||||
|
|||||||
@@ -1,17 +1,9 @@
|
|||||||
#include "lex.yy.h"
|
#include "lex.yy.h"
|
||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
#include "../string/string.h"
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
void lexer(LexerState state) {
|
void lexer(LexerState state) {
|
||||||
yyscan_t scanner;
|
yyscan_t scanner;
|
||||||
|
|
||||||
char *unquoted = unquote(state.content);
|
|
||||||
if (unquoted) {
|
|
||||||
printf("%s\n", unquoted);
|
|
||||||
free(unquoted);
|
|
||||||
}
|
|
||||||
|
|
||||||
yylex_init(&scanner);
|
yylex_init(&scanner);
|
||||||
|
|
||||||
yyset_extra(&state, scanner);
|
yyset_extra(&state, scanner);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
|
|
||||||
TokenStruct* init_token() {
|
TokenStruct* init_token() {
|
||||||
TokenStruct *tokenStruct = malloc(sizeof(TokenStruct));\
|
TokenStruct *tokenStruct = malloc(sizeof(TokenStruct));
|
||||||
if (tokenStruct == NULL) {
|
if (tokenStruct == NULL) {
|
||||||
// handle malloc failure
|
// handle malloc failure
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
@@ -68,19 +68,20 @@ typedef struct {
|
|||||||
TokenType type;
|
TokenType type;
|
||||||
int line;
|
int line;
|
||||||
int column;
|
int column;
|
||||||
char* value;
|
char *value;
|
||||||
} Token;
|
} Token;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int count;
|
int count;
|
||||||
int capacity;
|
int capacity;
|
||||||
Token* tokens;
|
Token *tokens;
|
||||||
} TokenStruct;
|
} TokenStruct;
|
||||||
|
|
||||||
TokenStruct* init_token();
|
TokenStruct *init_token();
|
||||||
|
|
||||||
void add_token(TokenStruct* token,TokenType type, const char* value, int line, int column);
|
void add_token(TokenStruct *token, TokenType type, const char *value, int line,
|
||||||
|
int column);
|
||||||
|
|
||||||
void free_tokens(TokenStruct* token);
|
void free_tokens(TokenStruct *token);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
10
src/main.c
10
src/main.c
@@ -1,5 +1,7 @@
|
|||||||
#include "lexer/lexer.h"
|
#include "lexer/lexer.h"
|
||||||
|
#include "parser/parser.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
@@ -46,9 +48,11 @@ int main() {
|
|||||||
};
|
};
|
||||||
lexer(state);
|
lexer(state);
|
||||||
free(content);
|
free(content);
|
||||||
for (int i = 0; i<tokenStruct->count; i++) {
|
|
||||||
printf("%d\n", tokenStruct->tokens[i].type);
|
TaggedValueStruct taggedValueStruct = init_TaggedValueStruct();
|
||||||
}
|
|
||||||
|
parser(&taggedValueStruct, tokenStruct, false);
|
||||||
|
|
||||||
free_tokens(tokenStruct);
|
free_tokens(tokenStruct);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
20
src/parser/parser.c
Normal file
20
src/parser/parser.c
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
TaggedValue parse_token(TokenStruct * tokenStruct, int *index) {
|
||||||
|
Token token = tokenStruct->tokens[*index];
|
||||||
|
switch (token.type) {
|
||||||
|
case TOKEN_STRING:
|
||||||
|
index++;
|
||||||
|
return parse_string(token);
|
||||||
|
default:
|
||||||
|
perror("unreachable");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parser(TaggedValueStruct * taggedValueStruct, TokenStruct * tokenStruct, bool inline_flag) {
|
||||||
|
int index = 0;
|
||||||
|
while (index < tokenStruct->count) {
|
||||||
|
TaggedValueStruct_append(taggedValueStruct, parse_token(tokenStruct, &index));
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/parser/parser.h
Normal file
9
src/parser/parser.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include "../lexer/token.h"
|
||||||
|
#include "string/string.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void parser(TaggedValueStruct * TaggedValueStruct, TokenStruct * tokenStruct, bool inline_flag);
|
||||||
|
|
||||||
|
TaggedValue parse_token(TokenStruct * tokenStruct, int *index);
|
||||||
78
src/parser/string/string.c
Normal file
78
src/parser/string/string.c
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
#include "string.h"
|
||||||
|
#include "../../lexer/token.h"
|
||||||
|
|
||||||
|
#include <cjson/cJSON.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
char *swap_quotes(const char *input) {
|
||||||
|
size_t len = strlen(input);
|
||||||
|
char *result = malloc(len + 1);
|
||||||
|
if (!result)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < len; ++i) {
|
||||||
|
if (input[i] == '"')
|
||||||
|
result[i] = '\'';
|
||||||
|
else if (input[i] == '\'')
|
||||||
|
result[i] = '"';
|
||||||
|
else
|
||||||
|
result[i] = input[i];
|
||||||
|
}
|
||||||
|
result[len] = '\0';
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *unquote(const char *str) {
|
||||||
|
if (*str == '\0')
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
char quote = str[0];
|
||||||
|
char *swapped = NULL;
|
||||||
|
char *unescaped = NULL;
|
||||||
|
|
||||||
|
if (quote == '\'') {
|
||||||
|
swapped = swap_quotes(str);
|
||||||
|
if (!swapped)
|
||||||
|
return NULL;
|
||||||
|
str = swapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON *json = cJSON_Parse(str);
|
||||||
|
if (!json || !cJSON_IsString(json)) {
|
||||||
|
if (swapped)
|
||||||
|
free(swapped);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy unescaped string before freeing JSON object
|
||||||
|
const char *decoded = cJSON_GetStringValue(json);
|
||||||
|
if (!decoded) {
|
||||||
|
cJSON_Delete(json);
|
||||||
|
if (swapped)
|
||||||
|
free(swapped);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
unescaped = strdup(decoded);
|
||||||
|
cJSON_Delete(json);
|
||||||
|
if (swapped)
|
||||||
|
free(swapped);
|
||||||
|
|
||||||
|
// If input was single-quoted, swap quotes back in the output
|
||||||
|
if (quote == '\'') {
|
||||||
|
char *final = swap_quotes(unescaped);
|
||||||
|
free(unescaped);
|
||||||
|
return final;
|
||||||
|
}
|
||||||
|
|
||||||
|
return unescaped;
|
||||||
|
}
|
||||||
|
|
||||||
|
TaggedValue parse_string(Token token) {
|
||||||
|
return (TaggedValue){
|
||||||
|
TYPE_STRING,
|
||||||
|
unquote(token.value)
|
||||||
|
};
|
||||||
|
}
|
||||||
8
src/parser/string/string.h
Normal file
8
src/parser/string/string.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include "../../lexer/token.h"
|
||||||
|
#include "../taggedValue.h"
|
||||||
|
|
||||||
|
char *swap_quotes(const char *input);
|
||||||
|
|
||||||
|
char *unquote(const char *str);
|
||||||
|
|
||||||
|
TaggedValue parse_string(Token token);
|
||||||
26
src/parser/taggedValue.c
Normal file
26
src/parser/taggedValue.c
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#include "taggedValue.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
TaggedValueStruct init_TaggedValueStruct() {
|
||||||
|
TaggedValueStruct taggedValueStruct = {
|
||||||
|
0,
|
||||||
|
INITIAL_CAPACITY,
|
||||||
|
malloc(sizeof(TaggedValue)*INITIAL_CAPACITY)
|
||||||
|
};
|
||||||
|
return taggedValueStruct;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaggedValueStruct_append(TaggedValueStruct *TaggedValueStruct,
|
||||||
|
TaggedValue TaggedValue) {
|
||||||
|
if (TaggedValueStruct->count >= TaggedValueStruct->capacity) {
|
||||||
|
TaggedValueStruct->capacity *= 2;
|
||||||
|
TaggedValueStruct->TaggedValue =
|
||||||
|
realloc(TaggedValueStruct->TaggedValue,
|
||||||
|
sizeof(TaggedValue) * TaggedValueStruct->capacity);
|
||||||
|
}
|
||||||
|
TaggedValueStruct[TaggedValueStruct->count].TaggedValue->data =
|
||||||
|
TaggedValue.data;
|
||||||
|
TaggedValueStruct[TaggedValueStruct->count].TaggedValue->type =
|
||||||
|
TaggedValue.type;
|
||||||
|
TaggedValueStruct->count++;
|
||||||
|
}
|
||||||
23
src/parser/taggedValue.h
Normal file
23
src/parser/taggedValue.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
typedef enum {
|
||||||
|
TYPE_STRING,
|
||||||
|
} ValueType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ValueType type;
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
} TaggedValue;
|
||||||
|
|
||||||
|
|
||||||
|
#define INITIAL_CAPACITY 64
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int count;
|
||||||
|
int capacity;
|
||||||
|
TaggedValue * TaggedValue;
|
||||||
|
} TaggedValueStruct;
|
||||||
|
|
||||||
|
TaggedValueStruct init_TaggedValueStruct();
|
||||||
|
void TaggedValueStruct_append(TaggedValueStruct *TaggedValueStruct,
|
||||||
|
TaggedValue TaggedValue);
|
||||||
@@ -3,65 +3,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <cjson/cJSON.h>
|
|
||||||
|
|
||||||
char *swap_quotes(const char *input) {
|
|
||||||
size_t len = strlen(input);
|
|
||||||
char *result = malloc(len + 1);
|
|
||||||
if (!result) return NULL;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < len; ++i) {
|
|
||||||
if (input[i] == '"') result[i] = '\'';
|
|
||||||
else if (input[i] == '\'') result[i] = '"';
|
|
||||||
else result[i] = input[i];
|
|
||||||
}
|
|
||||||
result[len] = '\0';
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *unquote(const char *str) {
|
|
||||||
if (*str == '\0') return NULL;
|
|
||||||
|
|
||||||
char quote = str[0];
|
|
||||||
char *swapped = NULL;
|
|
||||||
char *unescaped = NULL;
|
|
||||||
|
|
||||||
if (quote == '\'') {
|
|
||||||
swapped = swap_quotes(str);
|
|
||||||
if (!swapped) return NULL;
|
|
||||||
str = swapped;
|
|
||||||
}
|
|
||||||
|
|
||||||
cJSON *json = cJSON_Parse(str);
|
|
||||||
if (!json || !cJSON_IsString(json)) {
|
|
||||||
if (swapped) free(swapped);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy unescaped string before freeing JSON object
|
|
||||||
const char *decoded = cJSON_GetStringValue(json);
|
|
||||||
if (!decoded) {
|
|
||||||
cJSON_Delete(json);
|
|
||||||
if (swapped) free(swapped);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
unescaped = strdup(decoded);
|
|
||||||
cJSON_Delete(json);
|
|
||||||
if (swapped) free(swapped);
|
|
||||||
|
|
||||||
// If input was single-quoted, swap quotes back in the output
|
|
||||||
if (quote == '\'') {
|
|
||||||
char *final = swap_quotes(unescaped);
|
|
||||||
free(unescaped);
|
|
||||||
return final;
|
|
||||||
}
|
|
||||||
|
|
||||||
return unescaped;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *WHITE_SPACE = " \t\n\r\f\v";
|
const char *WHITE_SPACE = " \t\n\r\f\v";
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,5 @@ char* cloneString(char* str);
|
|||||||
|
|
||||||
void stripString(char* str, const char* chars);
|
void stripString(char* str, const char* chars);
|
||||||
|
|
||||||
char *swap_quotes(const char *input);
|
|
||||||
|
|
||||||
char *unquote(const char *str);
|
|
||||||
|
|
||||||
|
|
||||||
#endif // CLONESTRING_H
|
#endif // CLONESTRING_H
|
||||||
|
|||||||
55
test.ar
55
test.ar
@@ -1,54 +1 @@
|
|||||||
import "url.ar" as url
|
"hello world"
|
||||||
|
|
||||||
let __makeFile(name, type, data) = do
|
|
||||||
let File = {name: name, type: type, data: data}
|
|
||||||
let save(path) = do
|
|
||||||
let file = file.write(path)
|
|
||||||
file.buffer(data)
|
|
||||||
file.close()
|
|
||||||
File.save = save
|
|
||||||
return File
|
|
||||||
|
|
||||||
let __multipart(req, res) = do
|
|
||||||
let boundary = buffer().from(req.headers["content-type"].splitN("boundary=", 2)[1])
|
|
||||||
let newLineSplit = buffer().from("\r\n\r\n")
|
|
||||||
let parts = req.buffer.body.split(boundary)
|
|
||||||
for (i from 0 to parts.length) do
|
|
||||||
let str = parts[i].to("string")
|
|
||||||
if (str == "" || str=="--" || str=="--\r\n") continue
|
|
||||||
str = null
|
|
||||||
let headers = {}
|
|
||||||
let lines = parts[i].splitN(newLineSplit, 2)
|
|
||||||
let headerLines = lines[0].to("string").split("\r\n")
|
|
||||||
for (j from 0 to headerLines.length) do
|
|
||||||
let header = headerLines[j].splitN(": ", 2)
|
|
||||||
if (header.length != 2) continue
|
|
||||||
headers[header[0].lower()] = header[1]
|
|
||||||
if (lines.length != 2) continue
|
|
||||||
let body = lines[1]
|
|
||||||
if (i != parts.length-1) do
|
|
||||||
body = body.slice(0, body.length-4)
|
|
||||||
if ("content-disposition" in headers) do
|
|
||||||
let disposition = headers["content-disposition"].split("; ")
|
|
||||||
if (disposition[0] == "form-data") do
|
|
||||||
let name = json.parse(disposition[1].splitN("=", 2)[1])
|
|
||||||
if (disposition.length >= 3) do
|
|
||||||
let filename = json.parse(disposition[2].splitN("=", 2)[1])
|
|
||||||
req.files[name] = __makeFile(filename, headers["content-type"], body)
|
|
||||||
else do
|
|
||||||
req.formdata[name] = body.to("string")
|
|
||||||
res.next()
|
|
||||||
|
|
||||||
|
|
||||||
let formdata(req, res) = do
|
|
||||||
req.formdata = {}
|
|
||||||
req.files = {}
|
|
||||||
|
|
||||||
if (req.method != "POST") return res.next()
|
|
||||||
if ("content-type" not in req.headers) return res.next()
|
|
||||||
let loweredContentType = req.headers["content-type"].lower()
|
|
||||||
if (loweredContentType.startswith("multipart/form-data")) return __multipart(req, res)
|
|
||||||
else if (loweredContentType.startswith("application/x-www-form-urlencoded")) req.formdata = url.decodeURLQuery(req.buffer.body.to("string"))
|
|
||||||
else if (loweredContentType.startswith("application/json")) req.formdata = json.parse(req.buffer.body.to("string"))
|
|
||||||
else req.files.file = __makeFile("file", req.headers["content-type"], req.buffer.body)
|
|
||||||
res.next()
|
|
||||||
Reference in New Issue
Block a user