Files
cground/src/parser.c

220 lines
7.3 KiB
C
Raw Normal View History

2025-11-23 13:37:08 +11:00
#include "parser.h"
#include "lexer.h"
2025-11-23 15:54:50 +11:00
#include "types.h"
2025-11-23 13:37:08 +11:00
#include <stdio.h>
2025-11-23 15:54:50 +11:00
#include <string.h>
#include <ctype.h>
2025-11-23 13:37:08 +11:00
GroundProgram createGroundProgram() {
GroundProgram gp;
gp.size = 0;
2025-11-23 15:54:50 +11:00
gp.instructions = NULL;
2025-11-23 13:37:08 +11:00
return gp;
}
void addInstructionToProgram(GroundProgram* gp, GroundInstruction instruction) {
gp->size++;
GroundInstruction* ptr = realloc(gp->instructions, gp->size * sizeof(GroundInstruction));
if (ptr == NULL) {
perror("Couldn't allocate memory for instruction");
2025-11-23 15:54:50 +11:00
exit(EXIT_FAILURE);
2025-11-23 13:37:08 +11:00
}
gp->instructions = ptr;
gp->instructions[gp->size - 1] = instruction;
}
void freeGroundProgram(GroundProgram* gp) {
2025-11-23 15:54:50 +11:00
for (size_t i = 0; i < gp->size; i++) {
2025-11-23 13:37:08 +11:00
freeGroundInstruction(&gp->instructions[i]);
}
2025-11-23 15:54:50 +11:00
free(gp->instructions);
gp->instructions = NULL;
gp->size = 0;
2025-11-23 13:37:08 +11:00
}
2025-11-23 15:54:50 +11:00
// Helper: Check if a string is an integer
static bool isInteger(const char* str) {
if (str == NULL || *str == '\0') return false;
size_t i = 0;
if (str[0] == '-' || str[0] == '+') i++;
if (str[i] == '\0') return false;
for (; str[i] != '\0'; i++) {
if (!isdigit(str[i])) return false;
}
return true;
}
// Helper: Check if a string is a double
static bool isDouble(const char* str) {
if (str == NULL || *str == '\0') return false;
bool hasDecimal = false;
size_t i = 0;
if (str[0] == '-' || str[0] == '+') i++;
if (str[i] == '\0') return false;
for (; str[i] != '\0'; i++) {
if (str[i] == '.') {
if (hasDecimal) return false;
hasDecimal = true;
} else if (!isdigit(str[i])) {
return false;
}
}
return hasDecimal;
}
// Helper: Parse an argument token into a GroundArg
static GroundArg parseArgument(const char* token) {
if (token[0] == '"') {
// String literal - remove quotes
size_t len = strlen(token);
char* strVal = strndup(token + 1, len - 2);
GroundValue val = createStringGroundValue(strVal);
free(strVal);
return createValueGroundArg(val);
}
else if (token[0] == '\'') {
// Char literal
char charVal = token[1];
return createValueGroundArg(createCharGroundValue(charVal));
}
else if (strcmp(token, "true") == 0) {
return createValueGroundArg(createBoolGroundValue(true));
}
else if (strcmp(token, "false") == 0) {
return createValueGroundArg(createBoolGroundValue(false));
}
else if (token[0] == '$') {
// Value reference
return createRefGroundArg(VALREF, token + 1);
}
else if (token[0] == '&') {
// Direct reference
return createRefGroundArg(DIRREF, token + 1);
}
else if (token[0] == '%') {
// Line reference or label
return createRefGroundArg(LINEREF, token + 1);
}
else if (token[0] == '!') {
// Function reference
return createRefGroundArg(FNREF, token + 1);
}
else if (token[0] == '-') {
// Could be type reference or negative number
if (strlen(token) > 1 && !isdigit(token[1])) {
// Type reference (e.g., -int, -string)
2025-11-23 16:32:54 +11:00
return createRefGroundArg(TYPEREF, token + 1);
2025-11-23 15:54:50 +11:00
}
}
// Try to parse as number
if (isInteger(token)) {
int64_t intVal = atoll(token);
return createValueGroundArg(createIntGroundValue(intVal));
}
else if (isDouble(token)) {
double dblVal = atof(token);
return createValueGroundArg(createDoubleGroundValue(dblVal));
}
// Unknown token type
fprintf(stderr, "Warning: Unknown argument type for token: %s\n", token);
return createRefGroundArg(VALREF, token);
}
// Helper: Convert instruction string to GroundInstType
static GroundInstType getInstructionType(const char* inst) {
if (strcmp(inst, "if") == 0) return IF;
if (strcmp(inst, "jump") == 0) return JUMP;
if (strcmp(inst, "end") == 0) return END;
if (strcmp(inst, "input") == 0 || strcmp(inst, "stdin") == 0) return INPUT;
if (strcmp(inst, "print") == 0 || strcmp(inst, "stdout") == 0) return PRINT;
if (strcmp(inst, "println") == 0 || strcmp(inst, "stdlnout") == 0) return PRINTLN;
if (strcmp(inst, "set") == 0) return SET;
if (strcmp(inst, "gettype") == 0) return GETTYPE;
if (strcmp(inst, "exists") == 0) return EXISTS;
if (strcmp(inst, "setlist") == 0) return SETLIST;
if (strcmp(inst, "setlistat") == 0) return SETLISTAT;
if (strcmp(inst, "getlistat") == 0) return GETLISTAT;
if (strcmp(inst, "getlistsize") == 0) return GETLISTSIZE;
if (strcmp(inst, "listappend") == 0) return LISTAPPEND;
if (strcmp(inst, "getstrsize") == 0) return GETSTRSIZE;
if (strcmp(inst, "getstrcharat") == 0) return GETSTRCHARAT;
if (strcmp(inst, "add") == 0) return ADD;
if (strcmp(inst, "subtract") == 0) return SUBTRACT;
if (strcmp(inst, "multiply") == 0) return MULTIPLY;
if (strcmp(inst, "divide") == 0) return DIVIDE;
if (strcmp(inst, "equal") == 0) return EQUAL;
if (strcmp(inst, "inequal") == 0) return INEQUAL;
if (strcmp(inst, "not") == 0) return NOT;
if (strcmp(inst, "greater") == 0) return GREATER;
if (strcmp(inst, "lesser") == 0) return LESSER;
if (strcmp(inst, "stoi") == 0) return STOI;
if (strcmp(inst, "stod") == 0) return STOD;
if (strcmp(inst, "tostring") == 0) return TOSTRING;
if (strcmp(inst, "fun") == 0) return FUN;
if (strcmp(inst, "return") == 0) return RETURN;
if (strcmp(inst, "endfun") == 0) return ENDFUN;
if (strcmp(inst, "pusharg") == 0) return PUSHARG;
if (strcmp(inst, "call") == 0) return CALL;
if (strcmp(inst, "struct") == 0) return STRUCT;
if (strcmp(inst, "endstruct") == 0) return ENDSTRUCT;
if (strcmp(inst, "init") == 0) return INIT;
if (strcmp(inst, "use") == 0) return USE;
if (strcmp(inst, "extern") == 0) return EXTERN;
fprintf(stderr, "Error: Unknown instruction: %s\n", inst);
exit(EXIT_FAILURE);
}
GroundProgram parseFile(const char* file) {
GroundProgram program = createGroundProgram();
// First, lex the file
LexedFile lexed = lexFile(file);
// Parse each line
for (size_t lineNum = 0; lineNum < lexed.lineCount; lineNum++) {
TokenLine line = lexed.lines[lineNum];
// Skip empty lines
if (line.count == 0) {
continue;
}
// Check if first token is a label
size_t tokenStart = 0;
if (line.tokens[0].text[0] == '@') {
2025-11-23 16:32:54 +11:00
GroundInstruction inst = createGroundInstruction(CREATELABEL);
addArgToInstruction(&inst, createRefGroundArg(LABEL, line.tokens[0].text + 1));
addInstructionToProgram(&program, inst);
continue;
2025-11-23 15:54:50 +11:00
}
// First non-label token is the instruction
const char* instToken = line.tokens[tokenStart].text;
GroundInstType instType = getInstructionType(instToken);
GroundInstruction inst = createGroundInstruction(instType);
// Parse remaining tokens as arguments
for (size_t i = tokenStart + 1; i < line.count; i++) {
GroundArg arg = parseArgument(line.tokens[i].text);
addArgToInstruction(&inst, arg);
}
addInstructionToProgram(&program, inst);
}
// Clean up lexed data
freeLexedFile(&lexed);
return program;
2025-11-23 13:37:08 +11:00
}