From 52e421d0c9007c8dc6b2b5fe57d491f3aed8e416 Mon Sep 17 00:00:00 2001 From: Alexander Rosenberg Date: Thu, 9 Apr 2026 23:27:34 -0700 Subject: [PATCH] Some work --- Makefile | 5 +- lc.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ lc.h | 17 +++++-- token.c | 34 +++++++++++++ token.h | 9 ++++ util.c | 13 +++++ util.h | 4 ++ 7 files changed, 218 insertions(+), 7 deletions(-) create mode 100644 util.c diff --git a/Makefile b/Makefile index 4125f98..86f558d 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ CFLAGS=-std=c11 -D_FILE_OFFSET_BITS=64 -D_POSIX_C_SOURCE=200112L -Wall -Wextra $ LD=gcc LDFLAGS=$(DEBUG_FLAGS) -lambda: main.o token.o lc.o +lambda: main.o token.o lc.o util.o $(LD) $(LDFLAGS) -o $@ $^ %.o: %.c @@ -19,4 +19,5 @@ clean: # Dependencies main.o: token.h lc.h token.o: token.h util.h -lc.o: lc.h token.h +lc.o: lc.h token.h util.h +util.o: util.h diff --git a/lc.c b/lc.c index d1afbf5..7963b46 100644 --- a/lc.c +++ b/lc.c @@ -1 +1,144 @@ #include "lc.h" + +#include "util.h" + +#include +#include + +static LambdaTerm *make_variable(char *name, size_t name_len) { + LambdaTerm *term = malloc_safe(sizeof(LambdaTerm)); + term->type = TYPE_VARIABLE; + term->v.name = name; + term->v.name_len = name_len; + return term; +} + +static LambdaTerm *make_lambda(char *arg, size_t arg_len, LambdaTerm *body) { + LambdaTerm *term = malloc_safe(sizeof(LambdaTerm)); + term->type = TYPE_LAMBDA; + term->l.arg = arg; + term->l.arg_len = arg_len; + term->l.body = body; + return term; +} + +static LambdaTerm *make_apply(LambdaTerm *func, LambdaTerm *arg) { + LambdaTerm *term = malloc_safe(sizeof(LambdaTerm)); + term->type = TYPE_APPLY; + term->a.func = func; + term->a.arg = arg; + return term; +} + +static bool is_lambda_term_token(const Token *tok) { + switch (tok->type) { + case TOKEN_BACKSLASH: + case TOKEN_OPEN_PAREN: + case TOKEN_CLOSE_PAREN: + case TOKEN_IDENT: + return true; + case TOKEN_LET: + case TOKEN_EVAL: + case TOKEN_CONF: + case TOKEN_EQUALS: + case TOKEN_COLON: + case TOKEN_DEFINE: + case TOKEN_REDUCE: + case TOKEN_EOF: + return false; + default: + abort(); + } +} + +enum OperatorType { + OPER_APPLY, + OPER_DEFINE, +}; + +struct OperatorStack { + struct OperatorStack *next; + Token src; + enum OperatorType type; +}; + +static struct OperatorStack *push_oper(struct OperatorStack *restrict stack, + const Token *restrict src, + enum OperatorType type) { + struct OperatorStack *new = malloc_safe(sizeof(struct OperatorStack)); + new->next = stack; + new->src = *src; + new->type = type; + return new; +} + +enum OperandType { + OPAND_TERM, + OPAND_OPEN_PAREN, + OPAND_DEF_BEGIN, +}; + +struct OperandStack { + struct OperandStack *next; + Token src; + enum OperandType type; + LambdaTerm *term; +}; + +static struct OperandStack *push_opand(struct OperandStack *restrict stack, + const Token *restrict src, + enum OperandType type, ...) { + struct OperandStack *new = malloc_safe(sizeof(struct OperandStack)); + new->next = stack; + new->src = *src; + new->type = type; + if (type == OPAND_TERM) { + va_list args; + va_start(args, type); + new->term = va_arg(args, LambdaTerm *); + va_end(args); + } + return new; +} + +static void apply_one(struct OperatorStack **oper_stack, + struct OperandStack **opand_stack, + ParseError *restrict err_out) { + if (!*oper_stack) { + abort(); + } else if () { + } +} + +LambdaTerm *read_lambda_term(TokenStream *restrict stream, + ParseError *restrict err_out) { + ParseError backup_err; + if (!err_out) { + err_out = &backup_err; + } + struct OperatorStack *oper_stack = NULL; + struct OperandStack *opand_stack = NULL; + Token tok; + while (true) { + if (!token_stream_peek(stream, &tok, err_out)) { + return false; + } else if (!is_lambda_term_token(&tok)) { + break; + } + token_stream_discard(stream, NULL); + switch (tok.type) { + case TOKEN_OPEN_PAREN: + opand_stack = push_opand(opand_stack, OPAND_OPEN_PAREN); + break; + case TOKEN_BACKSLASH: + opand_stack = push_opand(opand_stack, OPAND_DEF_BEGIN); + break; + case TOKEN_CLOSE_PAREN: + case TOKEN_IDENT: + case TOKEN_DEFINE: + break; + default: + abort(); + } + } +} diff --git a/lc.h b/lc.h index 2f1c437..19cea08 100644 --- a/lc.h +++ b/lc.h @@ -1,6 +1,8 @@ #ifndef INCLUDED_TERM_H #define INCLUDED_TERM_H +#include "token.h" + #include typedef enum { @@ -14,17 +16,22 @@ struct _LambdaTerm { LambdaTermType type; union { struct { - char name; + char *name; + size_t name_len; } v; struct { - char argument; + char *arg; + size_t arg_len; LambdaTerm *body; } l; struct { - char function; - LambdaTerm *argument; - }; + LambdaTerm *func; + LambdaTerm *arg; + } a; }; }; +LambdaTerm *read_lambda_term(TokenStream *restrict stream, + ParseError *restrict err_out); + #endif diff --git a/token.c b/token.c index 47f48de..1a1ccec 100644 --- a/token.c +++ b/token.c @@ -136,11 +136,32 @@ static bool read_next_ident(TokenStream *restrict stream, Token *restrict out); static bool read_next_reduce(TokenStream *restrict stream, Token *restrict out, ParseError *restrict error); +bool token_stream_peek(TokenStream *restrict stream, Token *restrict out, + ParseError *restrict error) { + if (error) { + error->set = false; + } + if (!stream->has_buffer) { + bool res = token_stream_next(stream, &stream->buffer, error); + if (!res) { + return false; + } + stream->has_buffer = true; + } + *out = stream->buffer; + return true; +} + bool token_stream_next(TokenStream *restrict stream, Token *restrict out, ParseError *restrict error) { if (error) { error->set = false; } + if (stream->has_buffer) { + stream->has_buffer = false; + *out = stream->buffer; + return true; + } restart: skip_whitespace(stream); int c = peekc(stream); @@ -232,3 +253,16 @@ static bool read_next_reduce(TokenStream *restrict stream, Token *restrict out, return false; } } + +bool token_stream_discard(TokenStream *restrict stream, + ParseError *restrict error) { + if (stream->has_buffer) { + stream->has_buffer = false; + if (error) { + error->set = false; + } + return true; + } + Token tok; + return token_stream_next(stream, &tok, error); +} diff --git a/token.h b/token.h index 32b7b51..0ad2542 100644 --- a/token.h +++ b/token.h @@ -50,6 +50,9 @@ typedef struct { SrcPos pos; const char *src; size_t src_len; + + bool has_buffer; + Token buffer; } TokenStream; typedef struct { @@ -66,6 +69,7 @@ inline static void token_stream_init(TokenStream *stream, const char *src, stream->pos.line_offset = 0; stream->src = src; stream->src_len = src_len; + stream->has_buffer = false; } inline static bool token_stream_is_eof(TokenStream *stream) { @@ -73,8 +77,13 @@ inline static bool token_stream_is_eof(TokenStream *stream) { } // return true on success, false on error +bool token_stream_peek(TokenStream *restrict stream, Token *restrict out, + ParseError *restrict error); bool token_stream_next(TokenStream *restrict stream, Token *restrict out, ParseError *restrict error); +bool token_stream_discard(TokenStream *restrict stream, + ParseError *restrict error); + static inline void parse_error_clear(ParseError *error) { error->set = false; } diff --git a/util.c b/util.c new file mode 100644 index 0000000..33d23c0 --- /dev/null +++ b/util.c @@ -0,0 +1,13 @@ +#include "util.h" + +#include + +void *malloc_safe(size_t size) { + void *ptr = malloc(size); + if (!ptr && size) { + static char message[] = "out of memory!\n"; + fwrite(message, 1, sizeof(message) - 1, stdout); + abort(); + } + return ptr; +} diff --git a/util.h b/util.h index 42bad49..42e6f21 100644 --- a/util.h +++ b/util.h @@ -11,4 +11,8 @@ # define ATTR_FORMAT(...) #endif +#include + +void *malloc_safe(size_t size); + #endif