293 lines
4.9 KiB
C
293 lines
4.9 KiB
C
#include <stdio.h>
|
|
#include <unistd.h>
|
|
|
|
#include "picrin.h"
|
|
#include "picrin/pair.h"
|
|
|
|
#if PIC_ENABLE_READLINE
|
|
# include <string.h>
|
|
# include <stdlib.h>
|
|
# include <readline/readline.h>
|
|
# include <readline/history.h>
|
|
#endif
|
|
|
|
#define CODE_MAX_LENGTH 1024
|
|
#define LINE_MAX_LENGTH 256
|
|
|
|
void
|
|
print_help(void)
|
|
{
|
|
const char *help =
|
|
"picrin scheme\n"
|
|
"\n"
|
|
"Usage: picrin [options] [file]\n"
|
|
"\n"
|
|
"Options:\n"
|
|
" -e [program] run one liner ecript\n"
|
|
" -h show this help";
|
|
|
|
puts(help);
|
|
}
|
|
|
|
int exit_status;
|
|
|
|
void
|
|
repl(pic_state *pic)
|
|
{
|
|
char code[CODE_MAX_LENGTH] = "", line[LINE_MAX_LENGTH];
|
|
char *read_line, *prompt;
|
|
pic_value v, vs;
|
|
struct pic_proc *proc;
|
|
int ai, n, i;
|
|
|
|
#if ! PIC_ENABLE_READLINE
|
|
char last_char;
|
|
int char_index;
|
|
#endif
|
|
|
|
ai = pic_gc_arena_preserve(pic);
|
|
|
|
while (1) {
|
|
prompt = code[0] == '\0' ? "> " : "* ";
|
|
|
|
#if DEBUG
|
|
printf("[current ai = %d]\n", ai);
|
|
#endif
|
|
|
|
#if PIC_ENABLE_READLINE
|
|
read_line = readline(prompt);
|
|
if (read_line == NULL) {
|
|
goto eof;
|
|
}
|
|
else {
|
|
strncpy(line, read_line, LINE_MAX_LENGTH - 1);
|
|
add_history(read_line);
|
|
free(read_line);
|
|
}
|
|
#else
|
|
printf(prompt);
|
|
|
|
char_index = 0;
|
|
while ((last_char = getchar()) != '\n') {
|
|
if (last_char == EOF)
|
|
goto eof;
|
|
if (char_index == LINE_MAX_LENGTH)
|
|
goto overflow;
|
|
line[char_index++] = last_char;
|
|
}
|
|
line[char_index] = '\0';
|
|
#endif
|
|
|
|
if (strlen(code) + strlen(line) >= CODE_MAX_LENGTH)
|
|
goto overflow;
|
|
strcat(code, line);
|
|
|
|
/* read */
|
|
n = pic_parse_cstr(pic, code, &vs);
|
|
if (n == PIC_PARSER_INCOMPLETE) { /* wait for more input */
|
|
goto next;
|
|
}
|
|
code[0] = '\0';
|
|
if (n == PIC_PARSER_ERROR) { /* parse error */
|
|
goto next;
|
|
}
|
|
|
|
for (i = 0; i < n; ++i) {
|
|
v = pic_car(pic, vs);
|
|
|
|
#if DEBUG
|
|
printf("[read: ");
|
|
pic_debug(pic, v);
|
|
printf("]\n");
|
|
#endif
|
|
|
|
/* eval */
|
|
proc = pic_codegen(pic, v);
|
|
if (proc == NULL) {
|
|
printf("compilation error: %s\n", pic->errmsg);
|
|
pic->errmsg = NULL;
|
|
goto next;
|
|
}
|
|
v = pic_apply(pic, proc, pic_nil_value());
|
|
if (pic_undef_p(v)) {
|
|
printf("runtime error: %s\n", pic->errmsg);
|
|
pic->errmsg = NULL;
|
|
goto next;
|
|
}
|
|
|
|
/* print */
|
|
printf("=> ");
|
|
pic_debug(pic, v);
|
|
printf("\n");
|
|
|
|
vs = pic_cdr(pic, vs);
|
|
}
|
|
|
|
next:
|
|
pic_gc_arena_restore(pic, ai);
|
|
}
|
|
|
|
eof:
|
|
puts("");
|
|
exit_status = 0;
|
|
return;
|
|
|
|
overflow:
|
|
puts("** [fatal] line input overflow");
|
|
exit_status = 1;
|
|
return;
|
|
}
|
|
|
|
void
|
|
exec_file(pic_state *pic, const char *fname)
|
|
{
|
|
FILE *file;
|
|
int n, i;
|
|
pic_value vs;
|
|
struct pic_proc *proc;
|
|
|
|
file = fopen(fname, "r");
|
|
if (file == NULL) {
|
|
fprintf(stderr, "fatal error: could not read %s\n", fname);
|
|
goto abort;
|
|
}
|
|
|
|
n = pic_parse_file(pic, file, &vs);
|
|
if (n <= 0) {
|
|
fprintf(stderr, "fatal error: %s broken\n", fname);
|
|
goto abort;
|
|
}
|
|
|
|
for (i = 0; i < n; ++i) {
|
|
pic_value v;
|
|
|
|
v = pic_car(pic, vs);
|
|
|
|
proc = pic_codegen(pic, v);
|
|
if (proc == NULL) {
|
|
fputs(pic->errmsg, stderr);
|
|
fprintf(stderr, "fatal error: %s compilation failure\n", fname);
|
|
goto abort;
|
|
}
|
|
|
|
v = pic_apply(pic, proc, pic_nil_value());
|
|
if (pic_undef_p(v)) {
|
|
fputs(pic->errmsg, stderr);
|
|
fprintf(stderr, "fatal error: %s evaluation failure\n", fname);
|
|
goto abort;
|
|
}
|
|
|
|
vs = pic_cdr(pic, vs);
|
|
}
|
|
|
|
return;
|
|
|
|
abort:
|
|
exit_status = 1;
|
|
return;
|
|
}
|
|
|
|
void
|
|
exec_string(pic_state *pic, const char *str)
|
|
{
|
|
int n, i;
|
|
pic_value vs, v;
|
|
struct pic_proc *proc;
|
|
int ai = pic_gc_arena_preserve(pic);
|
|
|
|
n = pic_parse_cstr(pic, str, &vs);
|
|
if (n < 0) {
|
|
goto abort;
|
|
}
|
|
|
|
for (i = 0; i < n; ++i) {
|
|
v = pic_car(pic, vs);
|
|
|
|
proc = pic_codegen(pic, v);
|
|
if (proc == NULL) {
|
|
goto abort;
|
|
}
|
|
v = pic_apply(pic, proc, pic_nil_value());
|
|
if (pic_undef_p(v)) {
|
|
goto abort;
|
|
}
|
|
|
|
vs = pic_cdr(pic, vs);
|
|
|
|
pic_gc_arena_restore(pic, ai);
|
|
}
|
|
|
|
return;
|
|
|
|
abort:
|
|
exit_status = 1;
|
|
return;
|
|
}
|
|
|
|
static char *fname;
|
|
static char *script;
|
|
|
|
enum {
|
|
NO_MODE = 0,
|
|
INTERACTIVE_MODE,
|
|
FILE_EXEC_MODE,
|
|
ONE_LINER_MODE,
|
|
} mode;
|
|
|
|
void
|
|
parse_opt(int argc, char *argv[])
|
|
{
|
|
int r;
|
|
|
|
while (~(r = getopt(argc, argv, "he:"))) {
|
|
switch (r) {
|
|
case 'h':
|
|
print_help();
|
|
exit(0);
|
|
case 'e':
|
|
script = optarg;
|
|
mode = ONE_LINER_MODE;
|
|
}
|
|
}
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
if (argc == 0) {
|
|
if (mode == NO_MODE)
|
|
mode = INTERACTIVE_MODE;
|
|
}
|
|
else {
|
|
fname = argv[0];
|
|
mode = FILE_EXEC_MODE;
|
|
}
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[], char **envp)
|
|
{
|
|
pic_state *pic;
|
|
|
|
pic = pic_open(argc, argv, envp);
|
|
|
|
parse_opt(argc, argv);
|
|
|
|
switch (mode) {
|
|
case NO_MODE:
|
|
puts("logic flaw");
|
|
abort();
|
|
case INTERACTIVE_MODE:
|
|
repl(pic);
|
|
break;
|
|
case FILE_EXEC_MODE:
|
|
exec_file(pic, fname);
|
|
break;
|
|
case ONE_LINER_MODE:
|
|
exec_string(pic, script);
|
|
break;
|
|
}
|
|
|
|
pic_close(pic);
|
|
|
|
return exit_status;
|
|
}
|