start implimenting a parser

This commit is contained in:
2025-05-27 17:19:09 +01:00
parent 3dedd7f348
commit 43bc7663fc
14 changed files with 241 additions and 195 deletions

View File

@@ -1,2 +1,3 @@
# Chloride # Chloride
An Argon interpreter written in C An Argon interpreter written in C

View File

@@ -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);

View File

@@ -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;

View File

@@ -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

View File

@@ -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
View 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
View 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);

View 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)
};
}

View 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
View 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
View 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);

View File

@@ -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";

View File

@@ -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
View File

@@ -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()