more stuff in C

This commit is contained in:
Alain Zscheile 2023-10-02 00:17:09 +02:00
parent a3a4d3add4
commit 7b93c98dae
6 changed files with 337 additions and 5 deletions

25
c/libyns/README.md Normal file
View 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
View 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;
}

View file

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

View file

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

View file

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