more stuff in C
This commit is contained in:
parent
a3a4d3add4
commit
7b93c98dae
25
c/libyns/README.md
Normal file
25
c/libyns/README.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
# libyns
|
||||
|
||||
yanais backend library.
|
||||
|
||||
## used prefixes
|
||||
|
||||
### enums
|
||||
|
||||
```
|
||||
YNSTK_* lexer token kind
|
||||
YNSLRK_* lexer result kind
|
||||
YNSLEX_* lexer e.g. error kind
|
||||
YNSPRS_* parser e.g. error kind
|
||||
YNSTRG_* codegen target
|
||||
YNSR_* representation/layout kind
|
||||
```
|
||||
|
||||
### structures and functions
|
||||
|
||||
```
|
||||
yns_* everything
|
||||
|
||||
yns_repr_* representation/layout stuff
|
||||
yns_lex_* lexer stuff
|
||||
```
|
115
c/libyns/lex.c
Normal file
115
c/libyns/lex.c
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Alain Zscheile <fogti+devel@ytrizja.de>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "yns.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
yns_lex_t yns_lex_new(FILE *inp) {
|
||||
yns_lex_t ret;
|
||||
ret.inp = inp;
|
||||
ret.offset = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool yns_lex_fmt_token(FILE *out, const yns_lex_token_t *tok) {
|
||||
if(fprintf(out, "at offset %zu: ", tok->offset) < 1)
|
||||
return false;
|
||||
|
||||
const char *nstr = 0;
|
||||
switch(tok->kind) {
|
||||
case YNST_LPAREN: nstr = "("; break;
|
||||
case YNST_RPAREN: nstr = ")"; break;
|
||||
case YNST_LBRACE: nstr = "{"; break;
|
||||
case YNST_RBRACE: nstr = "}"; break;
|
||||
case YNST_LARR: nstr = "←"; break;
|
||||
case YNST_RARR: nstr = "→"; break;
|
||||
case YNST_LDUBARR: nstr = "⇐"; break;
|
||||
case YNST_RDUBARR: nstr = "⇒"; break;
|
||||
case YNST_CARET: nstr = "^"; break;
|
||||
case YNST_DOT: nstr = "."; break;
|
||||
case YNST_DUBCOLON: nstr = ":"; break;
|
||||
case YNST_SEMICOLON: nstr = ";"; break;
|
||||
case YNST_ASSIGN: nstr = "="; break;
|
||||
|
||||
case YNST_DATA: nstr = "data"; break;
|
||||
case YNST_LAMBDA: nstr = "λ"; break;
|
||||
case YNST_LET: nstr = "let"; break;
|
||||
case YNST_REPR: nstr = "repr"; break;
|
||||
case YNST_TYLAMBDA: nstr = "π"; break;
|
||||
case YNST_MU: nstr = "μ"; break;
|
||||
case YNST_MATCH: nstr = "match"; break;
|
||||
case YNST_MUTABLE: nstr = "mut"; break;
|
||||
|
||||
case YNST_IDENT:
|
||||
if(fprintf(out, "%.*s", (int) tok->data.len, tok->data.ptr) < 1)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case YNST_PATOUT:
|
||||
if(fprintf(out, "$%.*s", (int) tok->data.len, tok->data.ptr) < 0)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case YNST_DOTIDENT:
|
||||
if(fprintf(out, ".%.*s", (int) tok->data.len, tok->data.ptr) < 0)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case YNST_SYMBOL:
|
||||
if(fprintf(out, ":%.*s", (int) tok->data.len, tok->data.ptr) < 0)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case YNST_INTEGER:
|
||||
if(fprintf(out, "%zu", *((const size_t *)tok->data.ptr)) < 0)
|
||||
return false;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(!"yns_fmt_token: got unknown token kind");
|
||||
return false;
|
||||
}
|
||||
if(nstr && fprintf(out, "\"%s\"", nstr) < 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void yns_lex_token_deinit(yns_lex_token_t *tok) {
|
||||
if(!tok) return;
|
||||
if(!tok->data.ptr) return;
|
||||
free((void *)tok->data.ptr);
|
||||
tok->data.len = 0;
|
||||
tok->data.ptr = 0;
|
||||
}
|
||||
|
||||
size_t yns_lex_token_getint(const yns_lex_token_t *tok) {
|
||||
assert(tok->kind == YNST_INTEGER);
|
||||
return *((const size_t *)(tok->data.ptr));
|
||||
}
|
||||
|
||||
void yns_lex_result_deinit(yns_lex_result_t *res) {
|
||||
if(!res) return;
|
||||
if(!res->data.ptr) return;
|
||||
free((void *)res->data.ptr);
|
||||
res->data.len = 0;
|
||||
res->data.ptr = 0;
|
||||
}
|
||||
|
||||
bool yns_lex_res_extract_token(yns_lex_result_t *res, yns_lex_token_t *tok) {
|
||||
if(!res || res->kind != YNSPRS_OK)
|
||||
return false;
|
||||
|
||||
yns_lex_token_deinit(tok);
|
||||
tok->kind = res->tok_kind;
|
||||
tok->data = res->data;
|
||||
tok->offset = res->offset;
|
||||
|
||||
// prevent double-free
|
||||
res->data.ptr = 0;
|
||||
res->data.len = 0;
|
||||
return true;
|
||||
}
|
|
@ -3,7 +3,7 @@ install_headers('yns.h')
|
|||
yns_cmflags = ['-fno-plt', '-Werror=return-type', '-Werror=type-limits', '-Werror=incompatible-pointer-types']
|
||||
|
||||
libyns = shared_library('yns',
|
||||
'qbe.c',
|
||||
'lex.c', 'parser.c', 'qbe.c',
|
||||
version: '0.0.0',
|
||||
c_args : [yns_cmflags, '-fno-exceptions', '-fno-unwind-tables'],
|
||||
# cpp_args : [yns_cmflags, '-fvisibility-inlines-hidden', '-fno-rtti'],
|
||||
|
|
51
c/libyns/parser.c
Normal file
51
c/libyns/parser.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Alain Zscheile <fogti+devel@ytrizja.de>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "yns.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void yns_prs_error_deinit(yns_prs_error_t *err) {
|
||||
if(!err) return;
|
||||
switch(err->kind) {
|
||||
case YNSLEX_UNHANDLED_CHAR:
|
||||
case YNSPRS_UNKNOWN_IDENT:
|
||||
free((void *)err->data.ptr);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool yns_prs_fmt_error(FILE *out, const yns_prs_error_t *err) {
|
||||
const char *nstr = 0;
|
||||
|
||||
switch(err->kind) {
|
||||
case YNSPRS_OK: nstr = "(no error)"; break;
|
||||
case YNSLEX_NONE: nstr = "(end of file)"; break;
|
||||
case YNSLEX_OFFSET_OVERFLOW: nstr = "offset overflowed"; break;
|
||||
case YNSLEX_EOF_IN_COMMENT: nstr = "end of file inside comment encountered"; break;
|
||||
|
||||
case YNSLEX_IO_ERROR:
|
||||
if(fputs(out, "I/O error: ") < 1)
|
||||
return false;
|
||||
nstr = strerror((int) err->data.len);
|
||||
break;
|
||||
|
||||
case YNSLEX_UNHANDLED_CHAR:
|
||||
{
|
||||
uint32_t charcode = (uint32_t) err->data.len;
|
||||
// TODO
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(nstr && fputs(out, nstr) < 1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "yns.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
bool yns_init_glb_env(const char *target, yns_glb_env_t *env) {
|
||||
|
@ -158,14 +159,14 @@ void yns_repr_add_to_opaque(const yns_glb_env_t *env, const yns_repr_t *rp, yns_
|
|||
break;
|
||||
|
||||
default:
|
||||
assert(!"yns_repr_add_to_opaque: unhandled case");
|
||||
assert(!"yns_repr_add_to_opaque: unhandled repr kind");
|
||||
}
|
||||
}
|
||||
|
||||
bool yns_repr_to_qbe(const yns_glb_env_t *env, const yns_repr_t *rp, FILE *out) {
|
||||
bool yns_repr_to_qbe(const yns_glb_env_t *env, FILE *out, const yns_repr_t *rp) {
|
||||
const char x = yns_repr_cs_to_qbe_ch(env, rp->cs);
|
||||
if(x) {
|
||||
if(fwrite("w", 1, 1, out) == 0) return false;
|
||||
if(fwrite(&x, 1, 1, out) == 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -177,3 +178,33 @@ bool yns_repr_to_qbe(const yns_glb_env_t *env, const yns_repr_t *rp, FILE *out)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
void yns_repr_deinit(yns_repr_t *rp) {
|
||||
switch(rp->cs) {
|
||||
case YNSR_I8:
|
||||
case YNSR_I16:
|
||||
case YNSR_I32:
|
||||
case YNSR_F32:
|
||||
case YNSR_F64:
|
||||
case YNSR_I64:
|
||||
case YNSR_POINTER:
|
||||
case YNSR_OPAQUE:
|
||||
break;
|
||||
|
||||
case YNSR_AGGR:
|
||||
case YNSR_UNION:
|
||||
{
|
||||
const yns_repr_struct_t rcd = rp->un.rcd;
|
||||
for(size_t i = 0; i < rcd.field_count; ++i) {
|
||||
yns_repr_deinit(&rcd.fields[i].rp);
|
||||
}
|
||||
free(rp->un.rcd.fields);
|
||||
rp->un.rcd.fields = 0;
|
||||
rp->un.rcd.field_count = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(!"yns_repr_deinit: unhandled repr kind");
|
||||
}
|
||||
}
|
||||
|
|
112
c/libyns/yns.h
112
c/libyns/yns.h
|
@ -16,6 +16,114 @@ typedef struct {
|
|||
const uint8_t *ptr;
|
||||
} yns_slice_t;
|
||||
|
||||
/** Parser **/
|
||||
|
||||
typedef size_t yns_lex_offset_t;
|
||||
|
||||
typedef enum {
|
||||
// "no error" placeholder
|
||||
YNSPRS_OK,
|
||||
|
||||
YNSLEX_NONE,
|
||||
YNSLEX_IO_ERROR,
|
||||
|
||||
YNSLEX_OFFSET_OVERFLOW,
|
||||
YNSLEX_EOF_IN_COMMENT,
|
||||
YNSLEX_UNHANDLED_CHAR,
|
||||
YNSLEX_INVALID_INT,
|
||||
|
||||
YNSPRS_UNEXPECTED_EOF,
|
||||
YNSPRS_UNEXPECTED_TOKEN,
|
||||
YNSPRS_EXPECTED,
|
||||
YNSPRS_UNKNOWN_IDENT,
|
||||
} yns_prs_errkd_t;
|
||||
|
||||
typedef struct {
|
||||
yns_prs_errkd_t kind;
|
||||
yns_slice_t data;
|
||||
yns_lex_offset_t offset;
|
||||
} yns_prs_error_t;
|
||||
|
||||
void yns_prs_error_deinit(yns_prs_error_t *err);
|
||||
|
||||
|
||||
|
||||
/** Lexer **/
|
||||
|
||||
typedef enum {
|
||||
YNST_LPAREN,
|
||||
YNST_RPAREN,
|
||||
YNST_LBRACE,
|
||||
YNST_RBRACE,
|
||||
YNST_LARR,
|
||||
YNST_RARR,
|
||||
YNST_LDUBARR,
|
||||
YNST_RDUBARR,
|
||||
YNST_CARET,
|
||||
YNST_DOT,
|
||||
YNST_DUBCOLON,
|
||||
YNST_SEMICOLON,
|
||||
YNST_ASSIGN,
|
||||
|
||||
YNST_DATA,
|
||||
YNST_LAMBDA,
|
||||
YNST_LET,
|
||||
YNST_REPR,
|
||||
YNST_TYLAMBDA,
|
||||
YNST_MU,
|
||||
YNST_MATCH,
|
||||
YNST_MUTABLE,
|
||||
|
||||
YNST_IDENT,
|
||||
YNST_PATOUT,
|
||||
YNST_DOTIDENT,
|
||||
YNST_SYMBOL,
|
||||
YNST_INTEGER,
|
||||
} yns_lex_tkd_t;
|
||||
|
||||
typedef struct {
|
||||
yns_lex_tkd_t kind;
|
||||
yns_slice_t data;
|
||||
yns_lex_offset_t offset;
|
||||
} yns_lex_token_t;
|
||||
|
||||
typedef union {
|
||||
yns_lex_token_t tok;
|
||||
yns_prs_error_t err;
|
||||
} yns_lex_resun_t;
|
||||
|
||||
typedef struct {
|
||||
yns_prs_errkd_t kind;
|
||||
yns_lex_tkd_t tok_kind;
|
||||
yns_slice_t data;
|
||||
yns_lex_offset_t offset;
|
||||
} yns_lex_result_t;
|
||||
|
||||
typedef struct {
|
||||
FILE *inp;
|
||||
yns_lex_offset_t offset;
|
||||
|
||||
// saved data from peeking
|
||||
// when peek_res.kind = YNSLRK_NONE -> None
|
||||
yns_lex_result_t peek_res;
|
||||
} yns_lex_t;
|
||||
|
||||
yns_lex_t yns_lex_new(FILE *inp);
|
||||
bool yns_lex_fmt_token(FILE *out, const yns_lex_token_t *tok);
|
||||
size_t yns_lex_token_getint(const yns_lex_token_t *tok);
|
||||
|
||||
static inline size_t yns_lex_token_len(const yns_lex_token_t *tok) {
|
||||
return tok->data.len;
|
||||
}
|
||||
|
||||
void yns_lex_token_deinit(yns_lex_token_t *tok);
|
||||
void yns_lex_result_deinit(yns_lex_result_t *res);
|
||||
|
||||
// extracts a token from a result,
|
||||
// transferring ownership of attached data during that.
|
||||
bool yns_lex_res_extract_token(yns_lex_result_t *res, yns_lex_token_t *tok);
|
||||
|
||||
|
||||
/** QBE **/
|
||||
|
||||
typedef enum {
|
||||
|
@ -96,4 +204,6 @@ bool yns_repr_is_base(const yns_glb_env_t *env, const yns_repr_t *rp);
|
|||
void yns_repr_add_to_opaque(const yns_glb_env_t *env, const yns_repr_t *rp, yns_repr_opaque_t *out);
|
||||
|
||||
// format representation to be usable by qbe
|
||||
bool yns_repr_to_qbe(const yns_glb_env_t *env, const yns_repr_t *rp, FILE *out);
|
||||
bool yns_repr_to_qbe(const yns_glb_env_t *env, FILE *out, const yns_repr_t *rp);
|
||||
|
||||
void yns_repr_deinit(yns_repr_t *rp);
|
||||
|
|
Loading…
Reference in a new issue