Skip to content

Commit c84076a

Browse files
committed
Add command line parameters
1 parent 4aa868a commit c84076a

3 files changed

Lines changed: 86 additions & 67 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ arguments when their number is > 1.
196196

197197
(reverse '(a b c)) ; -> (c b a)
198198
(reverse "1234") ; -> "4321"
199-
(reverse '(a) b "c") ; -> ("c" b (a))
199+
(reverse '((a) b "c") ; -> ("c" b (a))
200200

201201
### Numeric operators
202202

src/minilisp.c

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,16 @@
1111
#include <string.h>
1212
#include "minilisp.h"
1313
#include "gc.h"
14+
#include "repl.h"
1415

1516
jmp_buf context;
1617

17-
__attribute((noreturn)) void error(char *fmt, ...) {
18+
extern filepos_t filepos;
19+
20+
void error(char *fmt, ...) {
1821
va_list ap;
1922
va_start(ap, fmt);
23+
fprintf(stderr, "%s %d: ", filepos.filename, filepos.line_num);
2024
vfprintf(stderr, fmt, ap);
2125
fprintf(stderr, "\n");
2226
va_end(ap);
@@ -100,7 +104,7 @@ static Obj *acons(void *root, Obj **x, Obj **y, Obj **a) {
100104
#define SYMBOL_MAX_LEN 200
101105
const char symbol_chars[] = "~!@#$%^&*-_=+:/?<>";
102106

103-
static Obj *read_expr(void *root);
107+
static Obj *read_expr(void *root, bool is_top_level);
104108

105109
static int peek(void) {
106110
char c = getchar();
@@ -130,8 +134,10 @@ static Obj *reverse(Obj *p) {
130134
static void skip_line(void) {
131135
for (;;) {
132136
char c = getchar();
133-
if (c == EOF || c == '\n')
137+
if (c == EOF || c == '\n'){
138+
filepos.line_num++;
134139
return;
140+
}
135141
if (c == '\r') {
136142
if (peek() == '\n')
137143
getchar();
@@ -145,14 +151,14 @@ static Obj *read_list(void *root) {
145151
DEFINE3(obj, head, last);
146152
*head = Nil;
147153
for (;;) {
148-
*obj = read_expr(root);
154+
*obj = read_expr(root, false);
149155
if (!*obj)
150156
error("Unclosed parenthesis");
151157
if (*obj == Cparen)
152158
return reverse(*head);
153159
if (*obj == Dot) {
154-
*last = read_expr(root);
155-
if (read_expr(root) != Cparen)
160+
*last = read_expr(root, false);
161+
if (read_expr(root, false) != Cparen)
156162
error("Closed parenthesis expected after dot");
157163
Obj *ret = reverse(*head);
158164
(*head)->cdr = *last;
@@ -178,7 +184,7 @@ static Obj *intern(void *root, char *name) {
178184
static Obj *read_quote(void *root) {
179185
DEFINE2(sym, tmp);
180186
*sym = intern(root, "quote");
181-
*tmp = read_expr(root);
187+
*tmp = read_expr(root, false);
182188
*tmp = cons(root, tmp, &Nil);
183189
*tmp = cons(root, sym, tmp);
184190
return *tmp;
@@ -235,10 +241,15 @@ static Obj *read_string(void *root) {
235241
return make_string(root, buf);
236242
}
237243

238-
static Obj *read_expr(void *root) {
244+
static Obj *read_expr(void *root, bool is_top_level) {
239245
for (;;) {
240246
char c = getchar();
241-
if (c == ' ' || c == '\n' || c == '\r' || c == '\t')
247+
if (c == '\n') {
248+
if (is_top_level) filepos.line_num++;
249+
if (peek() == '\r');
250+
continue;
251+
}
252+
if (c == ' ' || c == '\r' || c == '\t')
242253
continue;
243254
if (c == EOF)
244255
return NULL;
@@ -314,7 +325,7 @@ static void print(Obj *obj) {
314325
default:
315326
error("Bug: print: Unknown tag type: %d", obj->type);
316327
}
317-
fflush(stdout);
328+
//puts("");
318329
}
319330

320331
// Returns the length of the given list. -1 if it's not a proper list.
@@ -738,7 +749,17 @@ static Obj *prim_load(void *root, Obj **env, Obj **list) {
738749
error("load: filename must be a string");
739750
}
740751
char *name = args->car->name;
741-
process_file(name, env, expr );
752+
753+
// Save old context and set up new one for error handling
754+
jmp_buf old_context;
755+
memcpy(&old_context, &context, sizeof(jmp_buf));
756+
757+
if (setjmp(context) == 0) {
758+
process_file(name, env, expr);
759+
}
760+
761+
// Restore old context
762+
memcpy(&context, &old_context, sizeof(jmp_buf));
742763
return Nil;
743764
}
744765

@@ -773,8 +794,8 @@ static Obj *prim_lambda(void *root, Obj **env, Obj **list) {
773794
}
774795

775796
static Obj *handle_defun(void *root, Obj **env, Obj **list, int type) {
776-
if ((*list)->car->type != TSYMBOL || (*list)->cdr->type != TCELL)
777-
error("Malformed defun");
797+
if (length(*list) < 3 || (*list)->car->type != TSYMBOL || (*list)->cdr->type != TCELL)
798+
error("Malformed defun: correct form is (defun <symbol> (<symbol> ...) expr ...)");
778799
DEFINE3(fn, sym, rest);
779800
*sym = (*list)->car;
780801
*rest = (*list)->cdr;
@@ -1012,7 +1033,7 @@ int eval_input(char *input, Obj **env, Obj **expr) {
10121033
if (setjmp(context) == 0){
10131034
Obj *result = NULL;
10141035
while (true) {
1015-
*expr = read_expr(root);
1036+
*expr = read_expr(root, true);
10161037
if (!*expr)
10171038
break;
10181039

@@ -1026,6 +1047,7 @@ int eval_input(char *input, Obj **env, Obj **expr) {
10261047

10271048
if (result) {
10281049
print(result);
1050+
putc('\n', stdout);
10291051
}
10301052

10311053
return 0;

src/repl.c

Lines changed: 49 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "../bestline/bestline.h"
88
#include "ketopt.h"
99
#include "gc.h"
10+
#include "repl.h"
1011
#include "minilisp.h"
1112

1213
int ends_with(const char *str, const char *suffix)
@@ -49,8 +50,12 @@ char *hints(const char *buf, const char **ansi1, const char **ansi2) {
4950
return NULL;
5051
}
5152

53+
// This struct keeps track of the current file/line being evaluated
54+
filepos_t filepos = {"", 0, 0};
55+
5256
void minilisp(char *text, size_t length, bool with_repl, Obj **env, Obj **expr) {
5357

58+
// Process file
5459
if(text != NULL){
5560
// Save old stdin
5661
FILE * old_stdin = stdin;
@@ -65,53 +70,40 @@ void minilisp(char *text, size_t length, bool with_repl, Obj **env, Obj **expr)
6570
fclose(stream);
6671
}
6772

68-
int max_iter = (with_repl) ? __INT_MAX__ : 0;
69-
for(int promptnum = 1; promptnum < max_iter; promptnum++) {
70-
char prompt[15] = "";
71-
sprintf(prompt, "%d:", promptnum);
72-
char *line = bestline(prompt);
73-
if(line == NULL) continue;
74-
75-
// Save old stdin
76-
FILE * old_stdin = stdin;
77-
// Open a memory stream
78-
FILE * stream = fmemopen(line, strlen(line), "r");
79-
// Redirect stdin to the in memory stream in order to use getchar()
80-
stdin = stream;
81-
82-
usleep(10000);
83-
84-
if (line[0] != '\0' && line[0] != '/') {
85-
int ok = eval_input(line, env, expr);
86-
if (ok == 0) {
73+
// REPL
74+
if (with_repl)
75+
for(int promptnum = 1;; promptnum++) {
76+
char prompt[15] = "";
77+
sprintf(prompt, "%d:", promptnum);
78+
char *line = bestline(prompt);
79+
if(line == NULL) continue;
80+
// Save old stdin
81+
FILE * old_stdin = stdin;
82+
// Open a memory stream
83+
FILE * stream = fmemopen(line, strlen(line), "r");
84+
// Redirect stdin to the in memory stream in order to use getchar()
85+
stdin = stream;
86+
87+
usleep(10000);
88+
89+
if (line[0] != '\0' && line[0] != '/') {
90+
eval_input(line, env, expr);
8791
bestlineHistoryAdd(line);
8892
bestlineHistorySave("history.txt");
93+
} else if (line[0] == '/') {
94+
fputs("Unreconized command: ", stdout);
95+
fputs(line, stdout);
96+
putchar('\n');
8997
}
90-
} else if (line[0] == '/') {
91-
fputs("Unreconized command: ", stdout);
92-
fputs(line, stdout);
93-
putchar('\n');
94-
}
9598

96-
free(line);
97-
// restore stdin
98-
stdin = old_stdin;
99-
fclose(stream);
100-
}
99+
free(line);
100+
// restore stdin
101+
stdin = old_stdin;
102+
fclose(stream);
103+
}
101104
}
102105

103-
__attribute((noreturn)) void error(char *fmt, ...);
104-
105-
// Duplicate a string
106-
static char *dup_string(const char *str) {
107-
const size_t len = strlen(str);
108-
char *copy = malloc(len + 1);
109-
if (copy){
110-
strcpy(copy, str);
111-
copy[len] = '\0';
112-
}
113-
return copy;
114-
}
106+
void error(char *fmt, ...);
115107

116108
static size_t read_file(char *fname, char **text) {
117109
size_t length = 0;
@@ -150,6 +142,10 @@ void process_file(char *fname, Obj **env, Obj **expr) {
150142
char *text;
151143
size_t len = read_file(fname, &text);
152144
if (len == 0) return;
145+
146+
filepos.filename = strdup(fname);
147+
filepos.file_len = len;
148+
filepos.line_num = 0;
153149

154150
// Save old stdin
155151
FILE *old_stdin = stdin;
@@ -173,11 +169,12 @@ void process_file(char *fname, Obj **env, Obj **expr) {
173169
stdin = old_stdin;
174170
fclose(stream);
175171
free(text);
172+
//if (filepos.filename) free(filepos.filename);
176173
}
177174

178175
static bool no_history = false;
179-
static int num_args = 0;
180176
static char *one_liner = NULL;
177+
static int num_files = 0;
181178
static char **filenames;
182179
static bool with_repl = true;
183180

@@ -223,7 +220,7 @@ void parse_args(int argc, char **argv) {
223220

224221
case 'x':
225222
case 300: // --exec "... lisp code ..."
226-
one_liner = dup_string(option.arg);
223+
one_liner = strdup(option.arg);
227224
break;
228225

229226
case 'H':
@@ -259,10 +256,10 @@ void parse_args(int argc, char **argv) {
259256
}
260257

261258
// regular arguments: run files
262-
filenames = (char **) malloc(argc * sizeof(char *));
263-
for (int i = option.ind; i < argc; i++) {
264-
filenames[i] = dup_string(argv[i]);
265-
printf("Executing %s\n", filenames[i]);
259+
num_files = argc - option.ind;
260+
filenames = (char **) malloc(num_files * sizeof(char *));
261+
for (int i = 1; i <= num_files; i++) {
262+
filenames[i-1] = strdup(argv[i]);
266263
}
267264
}
268265

@@ -273,10 +270,12 @@ int main(int argc, char **argv) {
273270
DEFINE2(env, expr);
274271
init_minilisp(env);
275272

276-
for (int i = 0; i < num_args; i++) {
277-
printf("%s", filenames[i]);
278-
process_file(filenames[i], env, expr);
273+
for (int i = 0; i < num_files; i++) {
274+
printf("Loading %s\n", filenames[i]);
275+
process_file(filenames[i], env, expr);
276+
free(filenames[i]);
279277
}
278+
free(filenames);
280279

281280
/* Set the completion callback. This will be called every time the
282281
* user uses the <tab> key. */
@@ -292,8 +291,6 @@ int main(int argc, char **argv) {
292291
fputs("Command history disengaged.", stdout);
293292
}
294293

295-
296-
//printf("%s\n", one_liner);
297294
size_t len = one_liner ? strlen(one_liner) : 0;
298295
minilisp(one_liner, len, with_repl, env, expr);
299296

0 commit comments

Comments
 (0)