/* * lali (Lali Another Lisp Implementation) * * Author: Daniel Cerqueira (dan.git@lispclub.com) * Maintainer: Daniel Cerqueira (dan.git@lispclub.com) * Version: 0.0 * Keywords: lali, lisp, implementation, interpreter, lisp1.5, * computer programming language * Homepage: https://gitlab.com/alexandre1985/lali * SPDX-License-Identifier: GPL-3.0-or-later * * Copyright (C) 2025 Daniel Cerqueira * * This file is part of lali. * * lali 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. * * This program 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 * this program; if not, see . * * * lali software is based on tiny-lisp * version from 2016, written by Matthias Pirstitz, which is released to public * domain under Unlicense . */ #include "liblali.h" #define YEARS "2025" // MAIN /////////////////////////////////////////////////////////////////////// void runFile(int infd, Object **env, GC_PARAM) { Stream stream = { STREAM_TYPE_FILE, .fd = infd }; GC_TRACE(gcObject, nil); if (setjmp(exceptionEnv)) return; // deal with shebang if (peekForward(&stream, true) == EOF) return; do { *gcObject = nil; *gcObject = readExpr(&stream, GC_ROOTS); evalExpr(gcObject, env, GC_ROOTS); } while (peekNext(&stream) != EOF); } void runREPL(int infd, Object **env, GC_PARAM) { Stream stream = { STREAM_TYPE_FILE, .fd = infd }; GC_TRACE(gcObject, nil); for (;;) { if (setjmp(exceptionEnv)) continue; for (;;) { *gcObject = nil; fputs("lali> ", stdout); fflush(stdout); if (peekNext(&stream) == EOF) { fputc('\n', stdout); return; } *gcObject = readExpr(&stream, GC_ROOTS); *gcObject = evalExpr(gcObject, env, GC_ROOTS); writeObject(*gcObject, true, stdout); fputc('\n', stdout); } } } int main(int argc, char *argv[]) { int options = 0; bool repl = false; bool close = false; bool quiet = false; if (argc >= 2) { if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { fprintf(stderr, "basic usages:\nnormal: %s [file]...\nclose stdin: %s -c [file]...\nrun repl: %s -r [-q] [file]...\n\nin normal mode, reads from standard input.\nwhen present, load file(s) at startup. can be used as library file(s).\n", argv[0], argv[0], argv[0]); return EXIT_SUCCESS; } else if (!strcmp(argv[1], "-c")) { options++; close = true; } else if (!strcmp(argv[1], "-r")) { options++; repl = true; if (argc > 2 && !strcmp(argv[2], "-q")) { options++; quiet = true; } } else if (!strcmp(argv[1], "-q")) { options++; quiet = true; if (argc > 2 && !strcmp(argv[2], "-r")) { options++; repl = true; } } else if (argv[1][0] == '-') { fprintf(stderr, "%s: unrecognized option, `%s'\n", argv[0], argv[1]); return EXIT_FAILURE; } } GC_PARAM = nil; if (setjmp(exceptionEnv)) return EXIT_FAILURE; symbols = nil; symbols = newCons(&nil, &symbols, GC_ROOTS); symbols = newCons(&n, &symbols, GC_ROOTS); symbols = newCons(&t, &symbols, GC_ROOTS); symbols = newCons(&f, &symbols, GC_ROOTS); GC_TRACE(gcEnv, newRootEnv(GC_ROOTS)); int fd = 0; if (argc > 1) { for (int i = ++options; i < argc; i++) { if ((fd = open(argv[i], O_RDONLY)) == -1) { fprintf(stderr, "%s: open() failed, %s\n", argv[0], strerror(errno)); return EXIT_FAILURE; } runFile(fd, gcEnv, GC_ROOTS); } } if (repl) { if(!isatty(STDIN_FILENO)) { fprintf(stderr, "%s: repl does not accept piping\n", argv[0]); return EXIT_FAILURE; } if (!quiet) fprintf(stdout, "lali Copyright (C) %s Daniel Cerqueira\n\nThis is free software: you are free to change and redistribute it,\nunder certain conditions.\nThis program comes with NO WARRANTY, to the extent permitted by law.\n", YEARS); runREPL(STDIN_FILENO, gcEnv, GC_ROOTS); } else if (!close) runFile(STDIN_FILENO, gcEnv, GC_ROOTS); return EXIT_SUCCESS; }