diff options
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | lib/Makefile.am | 16 | ||||
| -rw-r--r-- | lib/aplwc.h | 11 | ||||
| -rw-r--r-- | lib/aplwc_internal.h | 63 | ||||
| -rw-r--r-- | lib/autocomplete.c | 24 | ||||
| -rw-r--r-- | lib/eval.c | 38 | ||||
| -rw-r--r-- | lib/exit.c | 28 | ||||
| -rw-r--r-- | lib/free_ast.c | 38 | ||||
| -rw-r--r-- | lib/free_eval_context.c | 70 | ||||
| -rw-r--r-- | lib/new.c | 11 | ||||
| -rw-r--r-- | lib/new_eval_context.c | 35 | ||||
| -rw-r--r-- | lib/output.c | 31 | ||||
| -rw-r--r-- | lib/parse.c | 100 | ||||
| -rw-r--r-- | lib/run_line.c | 34 | ||||
| -rw-r--r-- | lib/running.c | 28 | ||||
| -rw-r--r-- | lib/scan_line.c | 161 | ||||
| -rw-r--r-- | lib/strdup.c | 32 | ||||
| -rw-r--r-- | lib/syscmd_error.c | 32 | ||||
| -rw-r--r-- | lib/syscmd_output.c | 32 | ||||
| -rw-r--r-- | lib/voutput.c | 30 | ||||
| -rw-r--r-- | po/da.po | 46 | ||||
| -rw-r--r-- | src/main.c | 9 | ||||
| -rw-r--r-- | src/readline.c | 2 | ||||
| -rw-r--r-- | src/syscmd.c | 51 |
24 files changed, 891 insertions, 34 deletions
@@ -48,3 +48,6 @@ aplwc-*.tar.* /scripts/publish-release-docs /doc/aplwc.cp /doc/aplwc.cps +/.gdb_history +/lib/.gdb_history +/src/.gdb_history diff --git a/lib/Makefile.am b/lib/Makefile.am index ac8555b..9644940 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -4,9 +4,23 @@ noinst_HEADERS = aplwc_internal.h libaplwc_la_SOURCES = \ autocomplete.c \ + eval.c \ + exit.c \ + free_ast.c \ + free_eval_context.c \ lookup_syscmd.c \ new.c \ - register_syscmd.c + new_eval_context.c \ + output.c \ + parse.c \ + register_syscmd.c \ + run_line.c \ + running.c \ + scan_line.c \ + strdup.c \ + syscmd_output.c \ + syscmd_error.c \ + voutput.c libaplwc_la_LDFLAGS = -version-info 0:0:0 diff --git a/lib/aplwc.h b/lib/aplwc.h index aef2495..6bfdf40 100644 --- a/lib/aplwc.h +++ b/lib/aplwc.h @@ -21,14 +21,23 @@ #ifndef APLWC_H #define APLWC_H +#include <stddef.h> +#include <stdbool.h> + struct aplwc; struct aplwc_syscmd { const char *name; + void (*run)(struct aplwc *, struct aplwc_syscmd *, char *); }; -struct aplwc *aplwc_new(void); +struct aplwc *aplwc_new(void *(*)(size_t), void (*)(void *), void *(*)(void *, size_t)); char **aplwc_autocomplete(struct aplwc *, const char *, int, int); void aplwc_register_syscmd(struct aplwc *, struct aplwc_syscmd *); +void aplwc_syscmd_error(struct aplwc *, struct aplwc_syscmd *, const char *, ...); +void aplwc_syscmd_output(struct aplwc *, struct aplwc_syscmd *, const char *, ...); +void aplwc_run_line(struct aplwc *, const char *); +void aplwc_exit(struct aplwc *); +bool aplwc_running(struct aplwc *); #endif /* APLWC_H */ diff --git a/lib/aplwc_internal.h b/lib/aplwc_internal.h index 99c16ee..dd676fb 100644 --- a/lib/aplwc_internal.h +++ b/lib/aplwc_internal.h @@ -21,11 +21,74 @@ #ifndef APLWC_INTERNAL_H #define APLWC_INTERNAL_H +#include <stdarg.h> +#include <stdbool.h> + +enum aplwc_token_tag { + APLWC_TOKEN_SYSCMD, + APLWC_TOKEN_SYSCMD_ARGS, + + APLWC_TOKEN_ERROR, +}; + +enum aplwc_ast_tag { + APLWC_AST_SYSCMD, + + APLWC_AST_ERROR, +}; + struct aplwc { + void *(*alloc)(size_t); + void (*free)(void *); + void *(*realloc)(void *, size_t); + struct aplwc_syscmd **syscmds; int n_syscmds; + bool running; +}; + +struct aplwc_eval_context { + struct aplwc *aplwc; + char *text; + size_t offset; + size_t length; + + size_t n_tokens; + struct aplwc_token **tokens; + + size_t token_offset; + struct aplwc_ast *ast; +}; + +struct aplwc_token { + enum aplwc_token_tag tag; + size_t offset_start; + size_t offset_end; + + union { + } data; +}; + +struct aplwc_ast { + enum aplwc_ast_tag tag; + + union { + struct { + struct aplwc_syscmd *syscmd; + char *args; + } syscmd; + } data; }; struct aplwc_syscmd *aplwc_lookup_syscmd(struct aplwc *, const char *); +struct aplwc_eval_context *aplwc_new_eval_context(struct aplwc *); +void aplwc_scan_line(struct aplwc_eval_context *, const char *); +void aplwc_parse(struct aplwc_eval_context *); +void aplwc_eval(struct aplwc_eval_context *); +void aplwc_free_eval_context(struct aplwc_eval_context *); +void aplwc_free_ast(struct aplwc *, struct aplwc_ast *); +char *aplwc_strdup(struct aplwc *, const char *); +void aplwc_output(struct aplwc *, const char *, ...); +void aplwc_voutput(struct aplwc *, const char *, va_list); #endif /* APLWC_INTERNAL_H */ diff --git a/lib/autocomplete.c b/lib/autocomplete.c index 12a8cdc..9a33ea3 100644 --- a/lib/autocomplete.c +++ b/lib/autocomplete.c @@ -44,10 +44,24 @@ aplwc_autocomplete(struct aplwc *aplwc, const char *line, int start, int end) memcpy(word, line+start, len); word[len] = 0; - if(start == 0 && word[0] == ')') - completions = generate(aplwc, word, completions_syscmd); + struct aplwc_eval_context *context = aplwc_new_eval_context(aplwc); + aplwc_scan_line(context, line); + struct aplwc_token *tok = NULL; + for(size_t i = 0; (i < context->n_tokens) && (tok == NULL); i++) + if(((size_t)start >= context->tokens[i]->offset_start) && ((size_t)end <= context->tokens[i]->offset_end + 1)) + tok = context->tokens[i]; + + if(tok) + switch(tok->tag) { + case APLWC_TOKEN_SYSCMD: + completions = generate(aplwc, word, completions_syscmd); + break; + default: + break; + } free(word); - + + aplwc_free_eval_context(context); return completions; } @@ -64,7 +78,7 @@ generate(struct aplwc *aplwc, const char *word, char *(*fn)(struct completion_st char *c; int index = 0; - while(c = fn(&state)){ + while((c = fn(&state))){ index++; completions = realloc(completions, sizeof(*completions) * (index + 1)); completions[index-1] = c; @@ -79,7 +93,7 @@ completions_syscmd(struct completion_state *state) { struct aplwc_syscmd *syscmd; - while(syscmd = state->aplwc->syscmds[state->num++]){ + while((syscmd = state->aplwc->syscmds[state->num++])){ const char *name = syscmd->name; if(strncmp(name, state->word+1, state->wordlen-1) == 0){ int len = strlen(name); diff --git a/lib/eval.c b/lib/eval.c new file mode 100644 index 0000000..6eaaddf --- /dev/null +++ b/lib/eval.c @@ -0,0 +1,38 @@ +/* Aplwc - A Programming Language With Constraints + * + * Copyright (C) 2026 Peter Mikkelsen <petermikkelsen10@gmail.com> + * + * This file is part of aplwc. + * + * Aplwc is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Aplwc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with aplwc. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <aplwc.h> +#include "aplwc_internal.h" + +void +aplwc_eval(struct aplwc_eval_context *context) +{ + struct aplwc_syscmd *syscmd; + + switch(context->ast->tag){ + case APLWC_AST_SYSCMD: + syscmd = context->ast->data.syscmd.syscmd; + syscmd->run(context->aplwc, syscmd, context->ast->data.syscmd.args); + break; + case APLWC_AST_ERROR: + printf("cannot evaluate since parsing failed\n"); + } +} diff --git a/lib/exit.c b/lib/exit.c new file mode 100644 index 0000000..d2c89b8 --- /dev/null +++ b/lib/exit.c @@ -0,0 +1,28 @@ +/* Aplwc - A Programming Language With Constraints + * + * Copyright (C) 2026 Peter Mikkelsen <petermikkelsen10@gmail.com> + * + * This file is part of aplwc. + * + * Aplwc is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Aplwc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with aplwc. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <aplwc.h> +#include "aplwc_internal.h" + +void +aplwc_exit(struct aplwc *aplwc) +{ + aplwc->running = false; +} diff --git a/lib/free_ast.c b/lib/free_ast.c new file mode 100644 index 0000000..5db6633 --- /dev/null +++ b/lib/free_ast.c @@ -0,0 +1,38 @@ +/* Aplwc - A Programming Language With Constraints + * + * Copyright (C) 2026 Peter Mikkelsen <petermikkelsen10@gmail.com> + * + * This file is part of aplwc. + * + * Aplwc is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Aplwc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with aplwc. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <aplwc.h> +#include "aplwc_internal.h" + +void +aplwc_free_ast(struct aplwc *aplwc, struct aplwc_ast *ast) +{ + if(ast == NULL) + return; + + switch(ast->tag){ + case APLWC_AST_SYSCMD: + break; + case APLWC_AST_ERROR: + break; + } + + aplwc->free(ast); +} diff --git a/lib/free_eval_context.c b/lib/free_eval_context.c new file mode 100644 index 0000000..5af5220 --- /dev/null +++ b/lib/free_eval_context.c @@ -0,0 +1,70 @@ +/* Aplwc - A Programming Language With Constraints + * + * Copyright (C) 2026 Peter Mikkelsen <petermikkelsen10@gmail.com> + * + * This file is part of aplwc. + * + * Aplwc is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Aplwc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with aplwc. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <aplwc.h> +#include "aplwc_internal.h" + +static void free_token(struct aplwc_eval_context *, struct aplwc_token *); +static void free_ast(struct aplwc_eval_context *, struct aplwc_ast *); + +void +aplwc_free_eval_context(struct aplwc_eval_context *context) +{ + context->aplwc->free(context->text); + for(size_t i = 0; i < context->n_tokens; i++) + free_token(context, context->tokens[i]); + free_ast(context, context->ast); + context->aplwc->free(context->tokens); + context->aplwc->free(context); +} + +static void +free_token(struct aplwc_eval_context *context, struct aplwc_token *tok) +{ + if(tok == NULL) + return; + + switch(tok->tag){ + case APLWC_TOKEN_SYSCMD: + break; + case APLWC_TOKEN_SYSCMD_ARGS: + break; + case APLWC_TOKEN_ERROR: + break; + } + + context->aplwc->free(tok); +} + +static void +free_ast(struct aplwc_eval_context *context, struct aplwc_ast *ast) +{ + if(ast == NULL) + return; + + switch(ast->tag){ + case APLWC_AST_SYSCMD: + break; + case APLWC_AST_ERROR: + break; + } + + context->aplwc->free(ast); +} @@ -24,13 +24,18 @@ #include "aplwc_internal.h" struct aplwc * -aplwc_new(void) +aplwc_new(void *(*alloc)(size_t), void (*free)(void *), void *(*realloc)(void *, size_t)) { - struct aplwc *aplwc = malloc(sizeof(*aplwc)); + struct aplwc *aplwc = alloc(sizeof(*aplwc)); memset(aplwc, 0, sizeof(*aplwc)); - aplwc->syscmds = malloc(sizeof(aplwc->syscmds[0])); + aplwc->alloc = alloc; + aplwc->free = free; + aplwc->realloc = realloc; + + aplwc->syscmds = aplwc->alloc(sizeof(aplwc->syscmds[0])); aplwc->syscmds[0] = NULL; + aplwc->running = true; return aplwc; } diff --git a/lib/new_eval_context.c b/lib/new_eval_context.c new file mode 100644 index 0000000..01b5656 --- /dev/null +++ b/lib/new_eval_context.c @@ -0,0 +1,35 @@ +/* Aplwc - A Programming Language With Constraints + * + * Copyright (C) 2026 Peter Mikkelsen <petermikkelsen10@gmail.com> + * + * This file is part of aplwc. + * + * Aplwc is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Aplwc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with aplwc. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <string.h> +#include <aplwc.h> +#include "aplwc_internal.h" + +struct aplwc_eval_context * +aplwc_new_eval_context(struct aplwc *aplwc) +{ + struct aplwc_eval_context *context = aplwc->alloc(sizeof(*context)); + memset(context, 0, sizeof(*context)); + + context->aplwc = aplwc; + + return context; +} diff --git a/lib/output.c b/lib/output.c new file mode 100644 index 0000000..87fa766 --- /dev/null +++ b/lib/output.c @@ -0,0 +1,31 @@ +/* Aplwc - A Programming Language With Constraints + * + * Copyright (C) 2026 Peter Mikkelsen <petermikkelsen10@gmail.com> + * + * This file is part of aplwc. + * + * Aplwc is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Aplwc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with aplwc. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <aplwc.h> +#include "aplwc_internal.h" + +void +aplwc_output(struct aplwc *aplwc, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + aplwc_voutput(aplwc, fmt, args); + va_end(args); +} diff --git a/lib/parse.c b/lib/parse.c new file mode 100644 index 0000000..0bf2396 --- /dev/null +++ b/lib/parse.c @@ -0,0 +1,100 @@ +/* Aplwc - A Programming Language With Constraints + * + * Copyright (C) 2026 Peter Mikkelsen <petermikkelsen10@gmail.com> + * + * This file is part of aplwc. + * + * Aplwc is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Aplwc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with aplwc. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <string.h> +#include <aplwc.h> +#include "aplwc_internal.h" + +static enum aplwc_token_tag peek(struct aplwc_eval_context *); +static struct aplwc_token *match(struct aplwc_eval_context *, enum aplwc_token_tag); +static void emit(struct aplwc_eval_context *, enum aplwc_ast_tag, struct aplwc_ast **); +static char *token_text(struct aplwc_eval_context *, struct aplwc_token *); +static void parse_syscmd(struct aplwc_eval_context *, struct aplwc_ast **); + +void +aplwc_parse(struct aplwc_eval_context *context) +{ + context->token_offset = 0; + + if(peek(context) == APLWC_TOKEN_SYSCMD) + parse_syscmd(context, &context->ast); + + if(context->ast == NULL) + emit(context, APLWC_AST_ERROR, &context->ast); +} + +static enum aplwc_token_tag +peek(struct aplwc_eval_context *context) +{ + enum aplwc_token_tag tag = -1; + + if(context->token_offset < context->n_tokens) + tag = context->tokens[context->token_offset]->tag; + return tag; +} + +static struct aplwc_token * +match(struct aplwc_eval_context *context, enum aplwc_token_tag tag) +{ + struct aplwc_token *tok = NULL; + + if(peek(context) == tag) + tok = context->tokens[context->token_offset++]; + return tok; +} + +static void +emit(struct aplwc_eval_context *context, enum aplwc_ast_tag tag, struct aplwc_ast **ast) +{ + if((*ast) != NULL) + aplwc_free_ast(context->aplwc, *ast); + + *ast = context->aplwc->alloc(sizeof(**ast)); + memset(*ast, 0, sizeof(**ast)); + (*ast)->tag = tag; +} + +static char * +token_text(struct aplwc_eval_context *context, struct aplwc_token *tok) +{ + size_t len = tok->offset_end - tok->offset_start + 1; + char *text = context->aplwc->alloc(len + 1); + memcpy(text, context->text + tok->offset_start, len); + text[len] = 0; + return text; +} + +static void +parse_syscmd(struct aplwc_eval_context *context, struct aplwc_ast **ast) +{ + struct aplwc_token *tok = match(context, APLWC_TOKEN_SYSCMD); + + char *name = token_text(context, tok); + struct aplwc_syscmd *syscmd = aplwc_lookup_syscmd(context->aplwc, name+1); + context->aplwc->free(name); + + if(syscmd){ + emit(context, APLWC_AST_SYSCMD, ast); + (*ast)->data.syscmd.syscmd = syscmd; + (*ast)->data.syscmd.args = aplwc_strdup(context->aplwc, ""); + }else + emit(context, APLWC_AST_ERROR, ast); +} diff --git a/lib/run_line.c b/lib/run_line.c new file mode 100644 index 0000000..22f6055 --- /dev/null +++ b/lib/run_line.c @@ -0,0 +1,34 @@ +/* Aplwc - A Programming Language With Constraints + * + * Copyright (C) 2026 Peter Mikkelsen <petermikkelsen10@gmail.com> + * + * This file is part of aplwc. + * + * Aplwc is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Aplwc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with aplwc. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <aplwc.h> +#include "aplwc_internal.h" + +void +aplwc_run_line(struct aplwc *aplwc, const char *line) +{ + struct aplwc_eval_context *context = aplwc_new_eval_context(aplwc); + + aplwc_scan_line(context, line); + aplwc_parse(context); + aplwc_eval(context); + aplwc_free_eval_context(context); +} diff --git a/lib/running.c b/lib/running.c new file mode 100644 index 0000000..3a235ff --- /dev/null +++ b/lib/running.c @@ -0,0 +1,28 @@ +/* Aplwc - A Programming Language With Constraints + * + * Copyright (C) 2026 Peter Mikkelsen <petermikkelsen10@gmail.com> + * + * This file is part of aplwc. + * + * Aplwc is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Aplwc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with aplwc. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <aplwc.h> +#include "aplwc_internal.h" + +bool +aplwc_running(struct aplwc *aplwc) +{ + return aplwc->running; +} diff --git a/lib/scan_line.c b/lib/scan_line.c new file mode 100644 index 0000000..811c7cb --- /dev/null +++ b/lib/scan_line.c @@ -0,0 +1,161 @@ +/* Aplwc - A Programming Language With Constraints + * + * Copyright (C) 2026 Peter Mikkelsen <petermikkelsen10@gmail.com> + * + * This file is part of aplwc. + * + * Aplwc is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Aplwc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with aplwc. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <string.h> +#include <aplwc.h> +#include "aplwc_internal.h" + +static void scan(struct aplwc_eval_context *); +static struct aplwc_token *emit(struct aplwc_eval_context *, enum aplwc_token_tag, size_t); +static bool at_end(struct aplwc_eval_context *); +static void skip_whitespace(struct aplwc_eval_context *); +static char peek(struct aplwc_eval_context *, size_t); +static void consume(struct aplwc_eval_context *, size_t); +static void give_up(struct aplwc_eval_context *); +static bool scan_syscmd(struct aplwc_eval_context *); + +void +aplwc_scan_line(struct aplwc_eval_context *context, const char *line) +{ + size_t linelen = strlen(line); + + if(context->text){ + size_t textlen = strlen(context->text); + context->text = context->aplwc->realloc(context->text, textlen + linelen + 2); + context->text[textlen] = '\n'; + memcpy(context->text+textlen+1, line, linelen + 1); + }else{ + context->text = context->aplwc->alloc(linelen+1); + memcpy(context->text, line, linelen + 1); + } + + if(context->tokens){ + for(size_t i = 0; i < context->n_tokens; i++) + context->aplwc->free(context->tokens[i]); + context->aplwc->free(context->tokens); + } + scan(context); +} + +static void +scan(struct aplwc_eval_context *context) +{ + context->n_tokens = 0; + context->tokens = NULL; + context->offset = 0; + context->length = strlen(context->text); + + while(!at_end(context)){ + bool scanned = false; + + skip_whitespace(context); + if(at_end(context)) + continue; + + if(context->n_tokens == 0) + scanned |= scan_syscmd(context); + + if(!scanned) + give_up(context); + } +} + +static struct aplwc_token * +emit(struct aplwc_eval_context *context, enum aplwc_token_tag tag, size_t length) +{ + struct aplwc_token *tok = context->aplwc->alloc(sizeof(*tok)); + context->n_tokens++; + context->tokens = context->aplwc->realloc(context->tokens, sizeof(*context->tokens) * context->n_tokens); + context->tokens[context->n_tokens-1] = tok; + + memset(tok, 0, sizeof(*tok)); + tok->tag = tag; + tok->offset_start = context->offset; + tok->offset_end = tok->offset_start + length - 1; + + consume(context, length); + + return tok; +} + +static bool +at_end(struct aplwc_eval_context *context) +{ + return context->offset == context->length; +} + +static void +skip_whitespace(struct aplwc_eval_context *context) +{ + for(;;){ + char c = peek(context, 0); + if((c == ' ') || (c == '\t')) + consume(context, 1); + else + break; + } +} + +static char +peek(struct aplwc_eval_context *context, size_t offset) +{ + size_t index = context->offset + offset; + if(index < context->length) + return context->text[index]; + else + return 0; +} + +static void +consume(struct aplwc_eval_context *context, size_t n) +{ + context->offset += n; +} + +static void +give_up(struct aplwc_eval_context *context) +{ + emit(context, APLWC_TOKEN_ERROR, context->length - context->offset); +} + +static bool +scan_syscmd(struct aplwc_eval_context *context) +{ + if(peek(context, 0) != ')') + return false; + + size_t len; + + /* Scan the syscmd itself */ + for(len = 1; !((peek(context, len) == 0) || (peek(context, len) == ' ')); len++); + emit(context, APLWC_TOKEN_SYSCMD, len); + + /* Skip the leading whitespace */ + skip_whitespace(context); + + /* Take the rest of the line as arguments */ + for(len = 0; !((peek(context, len) == 0) || (peek(context, len) == '\n')); len++) + printf("arglen = %zu\n", len); + if(len > 0) + emit(context, APLWC_TOKEN_SYSCMD_ARGS, len); + + return true; +} diff --git a/lib/strdup.c b/lib/strdup.c new file mode 100644 index 0000000..3629de6 --- /dev/null +++ b/lib/strdup.c @@ -0,0 +1,32 @@ +/* Aplwc - A Programming Language With Constraints + * + * Copyright (C) 2026 Peter Mikkelsen <petermikkelsen10@gmail.com> + * + * This file is part of aplwc. + * + * Aplwc is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Aplwc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with aplwc. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <string.h> +#include <aplwc.h> +#include "aplwc_internal.h" + +char * +aplwc_strdup(struct aplwc *aplwc, const char *str) +{ + size_t len = strlen(str) + 1; + char *x = aplwc->alloc(len); + memcpy(x, str, len); + return x; +} diff --git a/lib/syscmd_error.c b/lib/syscmd_error.c new file mode 100644 index 0000000..edee676 --- /dev/null +++ b/lib/syscmd_error.c @@ -0,0 +1,32 @@ +/* Aplwc - A Programming Language With Constraints + * + * Copyright (C) 2026 Peter Mikkelsen <petermikkelsen10@gmail.com> + * + * This file is part of aplwc. + * + * Aplwc is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Aplwc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with aplwc. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <aplwc.h> +#include "aplwc_internal.h" + +void +aplwc_syscmd_error(struct aplwc *aplwc, struct aplwc_syscmd *syscmd, const char *fmt, ...) +{ + (void)aplwc; + (void)syscmd; + (void)fmt; + printf("bla"); +} diff --git a/lib/syscmd_output.c b/lib/syscmd_output.c new file mode 100644 index 0000000..3e8702d --- /dev/null +++ b/lib/syscmd_output.c @@ -0,0 +1,32 @@ +/* Aplwc - A Programming Language With Constraints + * + * Copyright (C) 2026 Peter Mikkelsen <petermikkelsen10@gmail.com> + * + * This file is part of aplwc. + * + * Aplwc is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Aplwc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with aplwc. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <aplwc.h> +#include "aplwc_internal.h" + +void +aplwc_syscmd_output(struct aplwc *aplwc, struct aplwc_syscmd *syscmd, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + aplwc_voutput(aplwc, fmt, args); + aplwc_output(aplwc, "\n"); + va_end(args); +} diff --git a/lib/voutput.c b/lib/voutput.c new file mode 100644 index 0000000..3f083ef --- /dev/null +++ b/lib/voutput.c @@ -0,0 +1,30 @@ +/* Aplwc - A Programming Language With Constraints + * + * Copyright (C) 2026 Peter Mikkelsen <petermikkelsen10@gmail.com> + * + * This file is part of aplwc. + * + * Aplwc is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Aplwc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with aplwc. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <aplwc.h> +#include "aplwc_internal.h" + +void +aplwc_voutput(struct aplwc *aplwc, const char *fmt, va_list args) +{ + (void)aplwc; + vprintf(fmt, args); +} @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: aplwc 0.1.6-fa0c-modified\n" "Report-Msgid-Bugs-To: bug-aplwc@gnu.org\n" -"POT-Creation-Date: 2026-04-03 19:30+0200\n" +"POT-Creation-Date: 2026-04-19 17:07+0200\n" "PO-Revision-Date: 2026-04-03 14:54+0200\n" "Last-Translator: <>\n" "Language-Team: Danish\n" @@ -16,22 +16,17 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Gtranslator 49.0\n" -#: src/main.c:68 +#: src/main.c:72 #, c-format -msgid "You typed: %s\n" -msgstr "Du skrev: %s\n" - -#: src/main.c:71 -#, c-format -msgid "bye\n" -msgstr "farvel\n" +msgid "Bye\n" +msgstr "" -#: src/main.c:78 +#: src/main.c:79 #, c-format msgid "Copyright (C) 2026 Peter Mikkelsen\n" msgstr "" -#: src/main.c:79 +#: src/main.c:80 #, c-format msgid "" "License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/" @@ -40,23 +35,46 @@ msgid "" "There is NO WARRANTY, to the extent permitted by law.\n" msgstr "" -#: src/main.c:88 +#: src/main.c:89 #, c-format msgid "" "Usage: %s [OPTION...]\n" "\n" msgstr "Brug: %s [TILVALG...]\n" -#: src/main.c:89 +#: src/main.c:90 #, c-format msgid " -h, --help display this help and exit\n" msgstr " -h, --help vis denne hjælp og afslut\n" -#: src/main.c:90 +#: src/main.c:91 #, c-format msgid " -v, --version display version information and exit\n" msgstr " -v, --version vis versionsinformation og afslut\n" +#: src/syscmd.c:56 src/syscmd.c:65 src/syscmd.c:74 +#, c-format +msgid "Unexpected: %s" +msgstr "" + +#: src/syscmd.c:58 +msgid "Version 0" +msgstr "" + +#: src/syscmd.c:76 +msgid "" +"Stats...\n" +"More stats..." +msgstr "" + +#, c-format +#~ msgid "You typed: %s\n" +#~ msgstr "Du skrev: %s\n" + +#, c-format +#~ msgid "bye\n" +#~ msgstr "farvel\n" + #, c-format #~ msgid "Hello from aplwc version '%s'\n" #~ msgstr "Hej fra aplwc version '%s'\n" @@ -1,3 +1,4 @@ + /* Aplwc - A Programming Language With Constraints * * Copyright (C) 2026 Peter Mikkelsen <petermikkelsen10@gmail.com> @@ -56,19 +57,19 @@ main(int argc, char *argv[]) } } - struct aplwc *aplwc = aplwc_new(); + struct aplwc *aplwc = aplwc_new(malloc, free, realloc); init_syscmds(aplwc); init_readline(aplwc); char *line; - while(line = readline(" ")){ + while(aplwc_running(aplwc) && (line = readline(" "))){ if(strlen(line) == 0) continue; add_history(line); - printf(_("You typed: %s\n"), line); + aplwc_run_line(aplwc, line); free(line); } - printf(_("bye\n")); + printf(_("Bye\n")); } static void diff --git a/src/readline.c b/src/readline.c index bda4df9..f03bbdb 100644 --- a/src/readline.c +++ b/src/readline.c @@ -24,7 +24,6 @@ static struct aplwc *aplwc; static char **completions; -static int completion_index; static char **complete(const char *, int, int); static char *get_completion(const char *, int); @@ -52,5 +51,6 @@ complete(const char *text, int start, int end) static char * get_completion(const char *text, int state) { + (void)text; return completions[state]; } diff --git a/src/syscmd.c b/src/syscmd.c index 6c3d2e5..8c3a88a 100644 --- a/src/syscmd.c +++ b/src/syscmd.c @@ -19,18 +19,59 @@ */ #include <config.h> +#include <string.h> #include "syscmd.h" +#include "nls.h" + +static void syscmd_version(struct aplwc *, struct aplwc_syscmd *, char *); +static void syscmd_exit(struct aplwc *, struct aplwc_syscmd *, char *); +static void syscmd_stats(struct aplwc *, struct aplwc_syscmd *, char *); static struct aplwc_syscmd syscmds[] = { - {.name = "help"}, - {.name = "version"}, - {.name = "reset"}, - {.name = "exit"}, + { + .name = "version", + .run = syscmd_version + }, + { + .name = "exit", + .run = syscmd_exit + }, + { + .name = "stats", + .run = syscmd_stats + }, }; void init_syscmds(struct aplwc *aplwc) { - for(int i = 0; i < (sizeof(syscmds)/sizeof(*syscmds)); i++) + for(size_t i = 0; i < (sizeof(syscmds)/sizeof(*syscmds)); i++) aplwc_register_syscmd(aplwc, &syscmds[i]); } + +static void +syscmd_version(struct aplwc *aplwc, struct aplwc_syscmd *syscmd, char *input) +{ + if(strlen(input) > 0) + aplwc_syscmd_error(aplwc, syscmd, _("Unexpected: %s")); + else + aplwc_syscmd_output(aplwc, syscmd, _("Version 0")); +} + +static void +syscmd_exit(struct aplwc *aplwc, struct aplwc_syscmd *syscmd, char *input) +{ + if(strlen(input) > 0) + aplwc_syscmd_error(aplwc, syscmd, _("Unexpected: %s")); + else + aplwc_exit(aplwc); +} + +static void +syscmd_stats(struct aplwc *aplwc, struct aplwc_syscmd *syscmd, char *input) +{ + if(strlen(input) > 0) + aplwc_syscmd_error(aplwc, syscmd, _("Unexpected: %s")); + else + aplwc_syscmd_output(aplwc, syscmd, _("Stats...\nMore stats...")); +} |