// FML parser // Michal Vlasák, FIT CTU, 2023 #pragma once #include <stddef.h> #include <stdlib.h> #include <stdint.h> #include <stdarg.h> #include <stdbool.h> #include <stdalign.h> #include <string.h> #include "arena.h" // See the bottom of this file for parser API. // This header mainly defines the AST emitted by the reference FML parser and // a few utility types. typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64; typedef int8_t i8; typedef int16_t i16; typedef int32_t i32; typedef int64_t i64; // `Str` is a pair of pointer and length and represents an immutable string. It // can be constructed from C string literals with the below `STR` macro. typedef struct { const u8 *str; size_t len; } Str; #define STR(lit) (Str) { .str = (const u8 *) lit, .len = sizeof(lit) - 1 } // Compare equality of strings, returns true if equal, false otherwise. bool str_eq(Str a, Str b); // Lexicographically compare two strings. Returns: // - 0 if the strings are equal, // - a negative number if the first string is less than the second // - a positive number if the first string is greater than the second int str_cmp(Str a, Str b); // See https://courses.fit.cvut.cz/NI-RUN/specs/ast.html for details about the // AST. typedef enum { AST_NULL, AST_BOOLEAN, AST_INTEGER, AST_ARRAY, AST_OBJECT, AST_FUNCTION, AST_DEFINITION, AST_VARIABLE_ACCESS, AST_VARIABLE_ASSIGNMENT, AST_INDEX_ACCESS, AST_INDEX_ASSIGNMENT, AST_FIELD_ACCESS, AST_FIELD_ASSIGNMENT, AST_FUNCTION_CALL, AST_METHOD_CALL, AST_CONDITIONAL, AST_LOOP, AST_PRINT, AST_BLOCK, AST_TOP, } AstKind; typedef struct { AstKind kind; } Ast; typedef struct { Ast base; } AstNull; typedef struct { Ast base; bool value; } AstBoolean; typedef struct { Ast base; i32 value; } AstInteger; typedef struct { Ast base; Ast *size; Ast *initializer; } AstArray; typedef struct { Ast base; Ast *extends; Ast **members; size_t member_cnt; } AstObject; typedef struct { Ast base; Str *parameters; size_t parameter_cnt; Ast *body; } AstFunction; typedef struct { Ast base; Str name; Ast *value; } AstDefinition; typedef struct { Ast base; Str name; } AstVariableAccess; typedef struct { Ast base; Str name; Ast *value; } AstVariableAssignment; typedef struct { Ast base; Ast *object; Ast *index; } AstIndexAccess; typedef struct { Ast base; Ast *object; Ast *index; Ast *value; } AstIndexAssignment; typedef struct { Ast base; Ast *object; Str field; } AstFieldAccess; typedef struct { Ast base; Ast *object; Str field; Ast *value; } AstFieldAssignment; typedef struct { Ast base; Ast *function; Ast **arguments; size_t argument_cnt; } AstFunctionCall; typedef struct { Ast base; Ast* object; Str name; Ast **arguments; size_t argument_cnt; } AstMethodCall; typedef struct { Ast base; Ast *condition; Ast *consequent; Ast *alternative; } AstConditional; typedef struct { Ast base; Ast *condition; Ast *body; } AstLoop; typedef struct { Ast base; Str format; Ast **arguments; size_t argument_cnt; } AstPrint; typedef struct { Ast base; Ast **expressions; size_t expression_cnt; } AstBlock; typedef struct { Ast base; Ast **expressions; size_t expression_cnt; } AstTop; // Parser takes a source code (`Str`) as input and produces AST (`Ast`) as an // output. The function `parse` is the most general way of using the parser. It // receives an `Arena` in which the `Ast` will be allocated (the user is // responsible for deallocation) and `GArena` which will be used as scratch // space (parser may allocate in it, but returns it to the previous state). // // In case of any encountered errors, `NULL` is ultimately returned, errors are // reported to the caller with a callback function and the space allocated in // the `Arena` by the parser is deallocated (restored to the state at the start // of parsing). // // For simplicity, the `parse_src` function can be used instead. It uses the // predefined example `parser_error_cb` callback, which is defined to report // errors to standard error (see it also for details about the callback // behavior). Ast *parse_src(Arena *arena, Str source); Ast *parse( Arena *arena, GArena *scratch, Str source, void (*error_callback)( void *user_data, const u8 *err_pos, const char *msg, va_list ap ), void *user_data ); void parser_error_cb( void *user_data, const u8 *err_pos, const char *msg, va_list ap );