diff --git a/src/c/compiler.d b/src/c/compiler.d index e4df7a143..045e49269 100644 --- a/src/c/compiler.d +++ b/src/c/compiler.d @@ -71,8 +71,6 @@ static int c_case(cl_object args, int flags); static int c_catch(cl_object args, int flags); static int c_compiler_let(cl_object args, int flags); static int c_cond(cl_object args, int flags); -static int c_dolist(cl_object args, int flags); -static int c_dotimes(cl_object args, int flags); static int c_eval_when(cl_object args, int flags); static int c_flet(cl_object args, int flags); static int c_funcall(cl_object args, int flags); @@ -102,6 +100,7 @@ static int c_tagbody(cl_object args, int flags); static int c_throw(cl_object args, int flags); static int c_unwind_protect(cl_object args, int flags); static int c_while(cl_object args, int flags); +static int c_until(cl_object args, int flags); static int compile_body(cl_object args, int flags); static int compile_form(cl_object args, int push); @@ -232,8 +231,6 @@ static compiler_record database[] = { {@'catch', c_catch, 1}, {@'ext::compiler-let', c_compiler_let, 0}, {@'cond', c_cond, 1}, - {@'dolist', c_dolist, 1}, - {@'dotimes', c_dotimes, 1}, {@'eval-when', c_eval_when, 0}, {@'flet', c_flet, 1}, {@'function', c_function, 1}, @@ -265,6 +262,7 @@ static compiler_record database[] = { {@'unwind-protect', c_unwind_protect, 1}, {@'values', c_values, 1}, {@'si::while', c_while, 0}, + {@'si::until', c_until, 0}, {NULL, NULL, 1} }; @@ -922,7 +920,7 @@ c_cond(cl_object args, int flags) { */ static int -c_while(cl_object body, int flags) { +c_while_until(cl_object body, int flags, bool is_while) { cl_object test = pop(&body); cl_index labelt, labelb; @@ -938,99 +936,20 @@ c_while(cl_object body, int flags) { /* Compile test */ asm_complete(OP_JMP, labelt); compile_form(test, FLAG_VALUES); - asm_op(OP_JNIL); + asm_op(is_while? OP_JT : OP_JNIL); asm_arg(labelb - current_pc()); return flags; } -/* - The OP_DOLIST & OP_DOTIMES operators save the lexical - environment and establishes a NIL block to execute the - enclosed forms, which iterate over the elements in a list or - over a range of integer numbers. At the exit of the block, - either by means of a OP_RETFROM jump or because of normal - termination, the lexical environment is restored, and all - bindings undone. - - [OP_DOTIMES/OP_DOLIST + labelz + labelo] - ... ; bindings - OP_EXIT - ... ; body - ... ; stepping forms - OP_EXIT - labelo: ... ; output form - OP_EXIT - labelz: - - */ - static int -c_dolist_dotimes(int op, cl_object args, int flags) { - cl_object head = pop(&args); - cl_object var = pop(&head); - cl_object list = pop(&head); - cl_object specials, body; - cl_index labelz, labelo; - cl_object old_variables = ENV->variables; - - body = c_process_declarations(args); - specials = VALUES(3); - - if (!SYMBOLP(var)) - FEillegal_variable_name(var); - - /* Compute list and enter loop */ - compile_form(list, FLAG_VALUES); - labelz = asm_jmp(op); - labelo = current_pc(); asm_arg(0); - - /* Bind block */ - c_register_block(Cnil); - - /* Initialize the variable */ - compile_form((op == OP_DOLIST)? Cnil : MAKE_FIXNUM(0), FLAG_REG0); - c_bind(var, specials); - asm_op(OP_EXIT); - - /* From here on, declarations apply */ - c_declare_specials(specials); - - /* Variable assignment and iterated body */ - compile_setq(OP_SETQ, var); - c_tagbody(body, 0); - asm_op(OP_EXIT); - - /* Output */ - asm_complete(0, labelo); - if (head != Cnil && CDR(head) != Cnil) - FEprogram_error("DOLIST: Too many output forms.", 0); - flags = maybe_values(flags); - if (Null(head)) { - compile_body(Cnil, flags); - } else { - compile_setq(OP_SETQ, var); - compile_form(pop(&head), flags); - } - asm_op(OP_EXIT); - - /* Exit point for block */ - asm_complete(op, labelz); - - ENV->variables = old_variables; - - return flags; -} - - -static int -c_dolist(cl_object args, int flags) { - return c_dolist_dotimes(OP_DOLIST, args, flags); +c_while(cl_object body, int flags) { + return c_while_until(body, flags, 1); } static int -c_dotimes(cl_object args, int flags) { - return c_dolist_dotimes(OP_DOTIMES, args, flags); +c_until(cl_object body, int flags) { + return c_while_until(body, flags, 0); } static int @@ -1053,7 +972,7 @@ c_eval_when(cl_object args, int flags) { ... fun2 ... - OP_EXIT + OP_UNBIND n labelz: */ static cl_index diff --git a/src/c/disassembler.d b/src/c/disassembler.d index 705d79acf..eb4b5b04f 100644 --- a/src/c/disassembler.d +++ b/src/c/disassembler.d @@ -110,70 +110,6 @@ NO_ARGS: /* -------------------- DISASSEMBLER CORE -------------------- */ -/* OP_DOLIST labelz, labelo - ... ; code to bind the local variable - OP_EXIT - ... ; code executed on each iteration - OP_EXIT - labelo: - ... ; code executed at the end - OP_EXIT - labelz: - - High level construct for the DOLIST iterator. The list over which - we iterate is stored in VALUES(0). -*/ -static cl_opcode * -disassemble_dolist(cl_object bytecodes, cl_opcode *vector) { - cl_opcode *exit, *output; - cl_object lex_old = cl_env.lex_env; - - GET_LABEL(exit, vector); - GET_LABEL(output, vector); - print_oparg("DOLIST\t", exit-base); - vector = disassemble(bytecodes, vector); - print_noarg("\t\t; dolist binding"); - vector = disassemble(bytecodes, vector); - print_noarg("\t\t; dolist body"); - vector = disassemble(bytecodes, vector); - print_noarg("\t\t; dolist"); - - cl_env.lex_env = lex_old; - return vector; -} - -/* OP_TIMES labelz, labelo - ... ; code to bind the local variable - OP_EXIT - ... ; code executed on each iteration - OP_EXIT - labelo: - ... ; code executed at the end - OP_EXIT - labelz: - - High level construct for the DOTIMES iterator. The number of times - we iterate is stored in VALUES(0). -*/ -static cl_opcode * -disassemble_dotimes(cl_object bytecodes, cl_opcode *vector) { - cl_opcode *exit, *output; - cl_object lex_old = cl_env.lex_env; - - GET_LABEL(exit, vector); - GET_LABEL(output, vector); - print_oparg("DOTIMES\t", exit-base); - vector = disassemble(bytecodes, vector); - print_noarg("\t\t; dotimes times"); - vector = disassemble(bytecodes, vector); - print_noarg("\t\t; dotimes body"); - vector = disassemble(bytecodes, vector); - print_noarg("\t\t; dotimes"); - - cl_env.lex_env = lex_old; - return vector; -} - /* OP_FLET nfun{arg} fun1{object} ... @@ -474,7 +410,7 @@ disassemble(cl_object bytecodes, cl_opcode *vector) { case OP_CATCH: string = "CATCH\t"; goto JMP; /* OP_EXIT - Marks the end of a high level construct (DOLIST, DOTIMES...) + Marks the end of a high level construct */ case OP_EXIT: print_noarg("EXIT"); return vector; @@ -655,10 +591,6 @@ disassemble(cl_object bytecodes, cl_opcode *vector) { */ case OP_NTHVAL: string = "NTHVAL\t"; goto NOARG; - case OP_DOLIST: vector = disassemble_dolist(bytecodes, vector); - break; - case OP_DOTIMES: vector = disassemble_dotimes(bytecodes, vector); - break; /* OP_DO label ... ; code executed within a NIL block OP_EXIT_FRAME diff --git a/src/c/interpreter.d b/src/c/interpreter.d index 57e66d6f0..d7929943a 100644 --- a/src/c/interpreter.d +++ b/src/c/interpreter.d @@ -446,116 +446,6 @@ interpret_funcall(cl_narg narg, cl_object fun) { /* -------------------- THE INTERPRETER -------------------- */ -/* OP_DOLIST labelz, labelo - ... ; code to bind the local variable - OP_EXIT - ... ; code executed on each iteration - OP_EXIT - labelo: - ... ; code executed at the end - OP_EXIT - labelz: - - High level construct for the DOLIST iterator. The list over which - we iterate is stored in VALUES(0). -*/ -static cl_opcode * -interpret_dolist(cl_object bytecodes, cl_opcode *vector) { - cl_opcode *volatile exit; - cl_opcode *output; - - GET_LABEL(exit, vector); - GET_LABEL(output, vector); - - /* 1) Set NIL block */ - CL_BLOCK_BEGIN(id) { - cl_object list = VALUES(0); - - bind_block(Cnil, id); - - /* 2) Build list & bind variable*/ - vector = interpret(bytecodes, vector); - - /* 3) Repeat until list is exahusted */ - while (!endp(list)) { - NVALUES = 1; - VALUES(0) = CAR(list); - interpret(bytecodes, vector); - list = CDR(list); - } - VALUES(0) = Cnil; - NVALUES = 1; - interpret(bytecodes, output); - - /* 4) Restore environment */ - cl_env.lex_env = cl_env.frs_top->frs_lex; - bds_unwind(cl_env.frs_top->frs_bds_top); - } CL_BLOCK_END; - return exit; -} - -/* OP_TIMES labelz, labelo - ... ; code to bind the local variable - OP_EXIT - ... ; code executed on each iteration - OP_EXIT - labelo: - ... ; code executed at the end - OP_EXIT - labelz: - - High level construct for the DOTIMES iterator. The number of times - we iterate is stored in VALUES(0). -*/ -static cl_opcode * -interpret_dotimes(cl_object bytecodes, cl_opcode *vector) { - cl_opcode *volatile exit; - cl_opcode *output; - - GET_LABEL(exit, vector); - GET_LABEL(output, vector); - - CL_BLOCK_BEGIN(id) { - cl_object length = VALUES(0); - - /* 1) Set up a nil block */ - bind_block(Cnil, id); - - /* 2) Retrieve number and bind variables */ - vector = interpret(bytecodes, vector); - - if (FIXNUMP(length)) { - cl_fixnum i, l = fix(length); - /* 3) Loop while needed */ - for (i = 0; i < l; i++) { - NVALUES = 1; - VALUES(0) = MAKE_FIXNUM(i); - interpret(bytecodes, vector); - } - length = MAKE_FIXNUM(i); - } else { - cl_object i; - for (i = MAKE_FIXNUM(0); - number_compare(i, length) < 0; - i = one_plus(i)) - { - NVALUES = 1; - VALUES(0) = i; - interpret(bytecodes, vector); - } - length = i; - } - NVALUES = 1; - VALUES(0) = length; - interpret(bytecodes, output); - - /* 4) Restore environment */ - cl_env.lex_env = cl_env.frs_top->frs_lex; - bds_unwind(cl_env.frs_top->frs_bds_top); - } CL_BLOCK_END; - return exit; -} - static cl_object close_around(cl_object fun, cl_object lex) { cl_object v = cl_alloc_object(t_bytecodes); @@ -569,7 +459,7 @@ close_around(cl_object fun, cl_object lex) { ... funn{object} ... - OP_EXIT + OP_UNBIND n Executes the enclosed code in a lexical enviroment extended with the functions "fun1" ... "funn". @@ -591,12 +481,12 @@ interpret_flet(cl_object bytecodes, cl_opcode *vector) { return vector; } -/* OP_FLET nfun{arg} +/* OP_LABELS nfun{arg} fun1{object} ... funn{object} ... - OP_EXIT + OP_UNBIND n Executes the enclosed code in a lexical enviroment extended with the functions "fun1" ... "funn". @@ -1055,7 +945,7 @@ interpret(cl_object bytecodes, void *pc) { /* OP_BLOCK label{arg} ... - OP_EXIT + OP_EXIT_FRAME label: Executes the enclosed code in a named block. @@ -1114,7 +1004,7 @@ interpret(cl_object bytecodes, void *pc) { ... labeln: ... - OP_EXIT + OP_EXIT_TAGBODY High level construct for the TAGBODY form. */ @@ -1159,14 +1049,6 @@ interpret(cl_object bytecodes, void *pc) { VALUES(0) = reg0 = Cnil; NVALUES = 0; break; - case OP_DOLIST: - vector = interpret_dolist(bytecodes, vector); - reg0 = VALUES(0); - break; - case OP_DOTIMES: - vector = interpret_dotimes(bytecodes, vector); - reg0 = VALUES(0); - break; case OP_MSETQ: vector = interpret_msetq(bytecodes, vector); reg0 = VALUES(0); @@ -1246,10 +1128,10 @@ interpret(cl_object bytecodes, void *pc) { } /* OP_PROTECT label ... ; code to be protected and whose value is output - OP_EXIT + OP_PROTECT_NORMAL label: ... ; code executed at exit - OP_EXIT + OP_PROTECT_EXIT High level construct for UNWIND-PROTECT. The first piece of code is executed and its output value is saved. Then the second piece of code diff --git a/src/c/symbols_list.h b/src/c/symbols_list.h index c1c8d6362..6bf58606b 100644 --- a/src/c/symbols_list.h +++ b/src/c/symbols_list.h @@ -1524,6 +1524,7 @@ cl_symbols[] = { #endif {SYS_ "WHILE", SI_ORDINARY, NULL, -1, OBJNULL}, +{SYS_ "UNTIL", SI_ORDINARY, NULL, -1, OBJNULL}, {SYS_ "QUASIQUOTE", SI_ORDINARY, NULL, -1, OBJNULL}, {SYS_ "*EXIT-HOOKS*", SI_SPECIAL, NULL, -1, Cnil}, diff --git a/src/c/symbols_list2.h b/src/c/symbols_list2.h index ea72a32a2..84b152e39 100644 --- a/src/c/symbols_list2.h +++ b/src/c/symbols_list2.h @@ -1524,6 +1524,7 @@ cl_symbols[] = { #endif {SYS_ "WHILE",NULL}, +{SYS_ "UNTIL",NULL}, {SYS_ "QUASIQUOTE",NULL}, {SYS_ "*EXIT-HOOKS*",NULL}, diff --git a/src/h/bytecodes.h b/src/h/bytecodes.h index 745101347..498c799ec 100644 --- a/src/h/bytecodes.h +++ b/src/h/bytecodes.h @@ -163,8 +163,6 @@ enum { OP_TAGBODY, OP_EXIT_TAGBODY, OP_EXIT_FRAME, - OP_DOLIST, - OP_DOTIMES, OP_PROTECT, OP_PROTECT_NORMAL, OP_PROTECT_EXIT, diff --git a/src/lsp/evalmacros.lsp b/src/lsp/evalmacros.lsp index 8e78cd932..d5d0bea21 100644 --- a/src/lsp/evalmacros.lsp +++ b/src/lsp/evalmacros.lsp @@ -247,7 +247,8 @@ SECOND-FORM." (defmacro multiple-value-bind (vars form &rest body) `(multiple-value-call #'(lambda (&optional ,@(mapcar #'list vars)) ,@body) ,form)) -(defmacro sys::while (test &body body) +(defun while-until (test body jmp-op) + (declare (si::c-local)) (let ((label (gensym)) (exit (gensym))) `(TAGBODY @@ -255,7 +256,13 @@ SECOND-FORM." ,label ,@body ,exit - (UNLESS ,test (GO ,label))))) + (,jmp-op ,test (GO ,label))))) + +(defmacro sys::while (test &body body) + (while-until test body 'when)) + +(defmacro sys::until (test &body body) + (while-until test body 'unless)) (defmacro case (keyform &rest clauses &aux (form nil) (key (gensym))) (dolist (clause (reverse clauses) @@ -276,25 +283,6 @@ SECOND-FORM." (defmacro return (&optional (val nil)) `(RETURN-FROM NIL ,val)) -(defmacro dolist ((var form &optional (val nil)) &rest body - &aux (temp (gensym)) decl) - (multiple-value-setq (decl body) - (find-declarations body)) - ;; Since ENDP did not complain, this is definitely a (CDR ,temp) is safe - `(DO* ((,temp ,form (CDR (THE CONS ,temp))) (,var)) - ((ENDP ,temp) ,val) - ,@decl - (SETQ ,var (CAR ,temp)) - ,@body - )) - -(defmacro dotimes ((var form &optional (val nil)) &rest body - &aux (temp (gensym))) - `(DO* ((,temp ,form) (,var 0 (1+ ,var))) - ((>= ,var ,temp) ,val) - (DECLARE (FIXNUM ,var)) ; Beppe (:READ-ONLY ,temp) - ,@body)) - ;; Declarations (defmacro declaim (&rest decl-specs) (if (cdr decl-specs) diff --git a/src/lsp/export.lsp b/src/lsp/export.lsp index bc662eae6..a1230cb8c 100644 --- a/src/lsp/export.lsp +++ b/src/lsp/export.lsp @@ -41,6 +41,56 @@ ;; This is also needed for booting ECL. In particular it is required in ;; defmacro.lsp. ;; +(let ((f #'(ext::lambda-block dolist (whole env) + (let (body pop finished control var expr exit) + (setq body (rest whole)) + (when (endp body) + (simple-program-error "Syntax error in ~A:~%~A" 'DOLIST whole)) + (setq control (first body) body (rest body)) + (when (endp control) + (simple-program-error "Syntax error in ~A:~%~A" 'DOLIST whole)) + (setq var (first control) control (rest control)) + (if (<= 1 (length control) 2) + (setq expr (first control) exit (rest control)) + (simple-program-error "Syntax error in ~A:~%~A" 'DOLIST whole)) + (multiple-value-bind (declarations body) + (process-declarations body nil) + `(block nil + (let* ((%dolist-var ,expr) + ,var) + (declare ,@declarations) + (si::while %dolist-var + (setq ,var (first %dolist-var)) + ,@body + (setq %dolist-var (rest %dolist-var))) + ,(when exit `(setq ,var nil)) + ,@exit))))))) + (si::fset 'dolist f t)) + +(let ((f #'(ext::lambda-block dotimes (whole env) + (let (body pop finished control var expr exit) + (setq body (rest whole)) + (when (endp body) + (simple-program-error "Syntax error in ~A:~%~A" 'DOTIMES whole)) + (setq control (first body) body (rest body)) + (when (endp control) + (simple-program-error "Syntax error in ~A:~%~A" 'DOTIMES whole)) + (setq var (first control) control (rest control)) + (if (<= 1 (length control) 2) + (setq expr (first control) exit (rest control)) + (simple-program-error "Syntax error in ~A:~%~A" 'DOTIMES whole)) + (multiple-value-bind (declarations body) + (process-declarations body nil) + `(block nil + (let* ((%dotimes-var ,expr) + (,var 0)) + (declare ,@declarations) + (si::while (< ,var %dotimes-var) + ,@body + (setq ,var (1+ ,var))) + ,@exit))))))) + (si::fset 'dotimes f t)) + (let ((f #'(ext::lambda-block do/do*-expand (whole env) (let (do/do* control test result vl step let psetq body) (setq do/do* (first whole) body (rest whole)) @@ -48,13 +98,13 @@ (setq let 'LET psetq 'PSETQ) (setq let 'LET* psetq 'SETQ)) (when (endp body) - (simple-program-error "Syntax error in DO/DO* body:~%~A" whole)) + (simple-program-error "Syntax error in ~A:~%~A" do/do* whole)) (setq control (first body) body (rest body)) (when (endp body) - (simple-program-error "Syntax error in DO/DO* body:~%~A" whole)) + (simple-program-error "Syntax error in ~A:~%~A" do/do* whole)) (setq test (first body) body (rest body)) (when (endp test) - (simple-program-error "Syntax error in DO/DO* body:~%~A" whole)) + (simple-program-error "Syntax error in ~A:~%~A" do/do* whole)) (setq result (rest test) test (first test)) (dolist (c control) (when (symbolp c) (setq c (list c))) @@ -65,15 +115,15 @@ (setq vl (cons (butlast c) vl) step (list* (third c) (first c) step))) (t - (simple-program-error "Syntax error in DO/DO* body:~%~A" whole)))) - (multiple-value-bind (declarations real-body doc) + (simple-program-error "Syntax error in ~A:~%~A" do/do* whole)))) + (multiple-value-bind (declarations real-body) (process-declarations body nil) `(BLOCK NIL (,let ,(nreverse vl) (declare ,@declarations) - (sys::while ,test - ,@real-body - ,@(when step (list (cons psetq (nreverse step))))) + (sys::until ,test + ,@real-body + ,@(when step (list (cons psetq (nreverse step))))) ,@(or result '(nil))))))))) (si::fset 'do f t) (si::fset 'do* f t))