196 lines
7.6 KiB
Plaintext
196 lines
7.6 KiB
Plaintext
|
$XFree86: xc/programs/xedit/lisp/README,v 1.12 2002/11/23 08:26:47 paulo Exp $
|
||
|
|
||
|
LAST UPDATED: $Date: 2006/11/25 20:34:53 $
|
||
|
|
||
|
|
||
|
SUMMARY
|
||
|
|
||
|
This is a small lisp interpreter for xedit. It implements a subset of
|
||
|
Common Lisp and the xedit package implements several of the basic Emacs
|
||
|
lisp functions.
|
||
|
|
||
|
(shared modules not broken, but needs a redesign for better performance,
|
||
|
but won't be made available in the default build probably for a long time,
|
||
|
it would be really better to generate the interface dinamically, and/or just
|
||
|
link agains't the required libraries and use a ffi interface)
|
||
|
+------------------------------------------------------------------------
|
||
|
| It has a very simple method for loading shared modules, slightly based on
|
||
|
| the XFree86 loader code, that is currently disabled by default. To enable it,
|
||
|
| edit lisp.cf and change BuildSharedLispModules to YES.
|
||
|
|
|
||
|
| Assuming you have built it with BuildSharedLispModules enabled, you can build
|
||
|
| a small test application can be built in this directory running "make lsp".
|
||
|
| Two lisp programs are available in the test directory. To test the programs
|
||
|
| run "./lsp test/hello.lsp" or "./lsp test/widgets.lsp".
|
||
|
+------------------------------------------------------------------------
|
||
|
|
||
|
Currently, it should be used as an helper and/or a small calculator embedded
|
||
|
in xedit. For the future it should be possible to write entire interfaces
|
||
|
in the xedit text buffers.
|
||
|
|
||
|
|
||
|
USAGE SUMMARY
|
||
|
|
||
|
To evaluate lisp expressions, put the text cursor just after the
|
||
|
lisp expression and press:
|
||
|
C-x,C-e - will evaluate it, and print the result to the message window
|
||
|
C-j - will evaluate it, and print the result to the edit window, any
|
||
|
errors are printed to the message window.
|
||
|
C-g - will send an SIGINT to the lisp process, and that process will
|
||
|
stop whatever it was processing and jump to the toplevel,
|
||
|
to wait for more input.
|
||
|
|
||
|
Note that C-j will only work in the *scratch* buffer.
|
||
|
|
||
|
|
||
|
NOTES
|
||
|
|
||
|
The improvements to xedit including the several possibilites to extend
|
||
|
the editor using Lisp are expected to allow making of xedit a versatile
|
||
|
text editor for programming, but there is code being (slowly) developed
|
||
|
that should also make it useable as a small word processor, for things
|
||
|
like WYSIWYG html, etc.
|
||
|
The xedit development is being done very slowly, maybe it will get
|
||
|
somewhere someday, but it is a pet/hobby project, there is no intention
|
||
|
of making of it an end user editor (the idea is to make it an useful
|
||
|
development tool).
|
||
|
In some aspects the development is trying to mimic several Emacs
|
||
|
features, but there is no intention of competition (if xedit ever get
|
||
|
something better than Emacs, I hope that it serves as a motivation to
|
||
|
make of Emacs an even better editor), actually it is expected to explore
|
||
|
different areas and use alternate solutions for the implementation.
|
||
|
Most work in a computer is done in a text editor and the more the editor
|
||
|
can help the user the better.
|
||
|
|
||
|
|
||
|
(debugger is broken and very slow, no prevision for fixing it, but is
|
||
|
expected to work correctly for interpreted only code)
|
||
|
+------------------------------------------------------------------------
|
||
|
| DEBUGGER
|
||
|
|
|
||
|
| There is a, currently, very simple debugger implement in the interpreter.
|
||
|
| The debugger is now optional, and off by default. To make it available,
|
||
|
| you need to recompile with -DDEBUGGER.
|
||
|
| To use the debugger, run the lsp sample program as "./lsp -d", and optionally
|
||
|
| pass a second parameter, for the file to be interpreted. Once the debugger
|
||
|
| prompt is visible, type "help" for a summary of options. To leave the debugger
|
||
|
| type "continue".
|
||
|
| Note that the debugger is still very simple, it won't work from xedit, and
|
||
|
| won't drop to the debugger on "fatal errors". It allows adding breakpoints to
|
||
|
| functions and watchpoints to variables. Support for changing data and going to
|
||
|
| the debugger on fatal errors should be added at some time.
|
||
|
+------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
COMPILER
|
||
|
|
||
|
Now there is a very simple bytecode compiler. It is far from finished, but
|
||
|
for simple code can show significant better performance.
|
||
|
There is not yet an interface to compile entire files and no interface to
|
||
|
store the generated bytecode in disk. There is an interface to bytecode
|
||
|
compile toplevel forms as a LAMBDA NIL, but it is not yet exported.
|
||
|
If your code needs to call GO/RETURN/RETURN-FROM as the result of an EVAL,
|
||
|
it must jump to code in the interpreter, after compiling all calls to
|
||
|
GO/RETURN/RETURN-FROM are just stack adjusting and jumps in the bytecode.
|
||
|
CATCH/THROW and UNWIND-PROTECT are running as interpreted code for now, so it
|
||
|
is safe to use these, but code in such blocks is not compiled/optimized
|
||
|
(not even macro expansion is done, as it understands that while not compiled,
|
||
|
everything is candidate to redefinition at any time).
|
||
|
To compile the code, just write a function, and compile it, example:
|
||
|
|
||
|
(defun fact (n)
|
||
|
(if (< n 2)
|
||
|
1
|
||
|
(* n (fact (1- n)))
|
||
|
)
|
||
|
)
|
||
|
FACT
|
||
|
|
||
|
(compile 'fact)
|
||
|
FACT
|
||
|
NIL
|
||
|
NIL
|
||
|
|
||
|
(disassemble 'fact)
|
||
|
Function FACT:
|
||
|
1 required argument: N
|
||
|
0 optional arguments
|
||
|
0 keyword parameters
|
||
|
No rest argument
|
||
|
|
||
|
Bytecode header:
|
||
|
1 element used in the stack
|
||
|
2 elements used in the builtin stack
|
||
|
0 elements used in the protected stack
|
||
|
Constant 0 = 1
|
||
|
Constant 1 = (2)
|
||
|
Symbol 0 = N
|
||
|
Builtin 0 = *
|
||
|
Builtin 1 = 1-
|
||
|
Builtin 2 = <
|
||
|
|
||
|
Initial stack:
|
||
|
0 = N
|
||
|
|
||
|
Bytecode stream:
|
||
|
0 LOAD&PUSH (0)
|
||
|
2 LOADCON&PUSH [1] ; (2)
|
||
|
4 CALL 2 [2] ; <
|
||
|
7 JUMPNIL 8
|
||
|
10 LOADCON [0] ; 1
|
||
|
12 NOOP
|
||
|
13 JUMP 19
|
||
|
16 LOAD&PUSH (0)
|
||
|
18 LOAD&PUSH (0)
|
||
|
20 CALL 1 [1] ; 1-
|
||
|
23 LET* [0] ; N
|
||
|
25 LETREC 1
|
||
|
27 UNLET 1
|
||
|
29 BCONS1
|
||
|
30 CALL 1 [0] ; *
|
||
|
33 RETURN
|
||
|
FACT
|
||
|
|
||
|
|
||
|
There are several optimizations that should be done at some time, I don't
|
||
|
think adding NOOP opcodes will help everywhere to make aligned memory reads
|
||
|
of shorts and ints.
|
||
|
It should have explicitly visible registers, not the abstraction of "the
|
||
|
current value", so the code generator can choose register allocation for
|
||
|
loop control variables, commonly used variables, etc, for example. Jumps
|
||
|
should have 3 types: byte relative, 2 bytes relative and 4 bytes relative.
|
||
|
For now there is only 2 byte relative jumps, byte relative jumps
|
||
|
can show a significant performance increase, but they are disable until
|
||
|
it is decided how inlined functions will work, if it just updates the bytecode
|
||
|
header and cut&past the bytecode, jumps must be updated, and some jumps
|
||
|
may not fit anymore in a byte.
|
||
|
|
||
|
|
||
|
OPTIMIZATION
|
||
|
|
||
|
There are plenty of possibilities to make the interpreter run faster. Some
|
||
|
optimizations that can make it run quite faster in certain cases are:
|
||
|
o Better object memory layout and gc. The current memory allocation code
|
||
|
is very bad, it try to keep 3 times more free objects than the currently
|
||
|
used number, this can consume a lot of memory. The reason is to reduce
|
||
|
the gc time cost so that it will in average miss only one in every 4
|
||
|
collect tries.
|
||
|
o Implement real vectors, currently they are just a list, so it cannot
|
||
|
just deference a given index, and gc time is very long also.
|
||
|
o Most lists are never changed once created, it could somehow add an index
|
||
|
field in the cons cell, so that NTH/NTHCDR/LENGTH like code could just
|
||
|
deference the correct object, instead of traversing the CDR of every
|
||
|
cons. This would probably require implementing lists as vectors, while
|
||
|
making it easy to deference would make life harder when deleting/inserting
|
||
|
sublists in a list. It should also better be done in a way that does
|
||
|
not require a lot of objects allocated linearly.
|
||
|
|
||
|
|
||
|
HELPING
|
||
|
|
||
|
Send comments and code to me (paulo@XFree86.Org) or to the XFree86
|
||
|
mailing/patch lists.
|
||
|
|
||
|
--
|
||
|
Paulo
|