There are a couple of editors which support syntax highlighting for Lisp.
Some of them also can highlight / find / jump to opening and closing brackets which
is one of the problems in Lisp for beginners (well not only for them ).
Here is a tiny list:
There are syntax highlighting files for ConTEXT (http://context.cx/highlighters.php?filter=A-D), UltraEdit and Notepad++. Notepad++ ships with CoCreate Modeling 2007 and later.
Es gibt eine Reihe von Editoren (Text-Bearbeitungs-Programmen), die auch die Programmiersprache Lisp unterstützen. Einige können auch das Auffinden von schliessenden und öffnenden Klammern erleichtern.
Eine kleine Liste von solchen Programmen findet sich hier:
Einige Editoren beherrschen automatische Syntaxhervorhebung, wie zum Beispiel ConTEXT (http://context.cx/highlighters.php?filter=A-D), UltraEdit and Notepad++. Notepad++ wird mit CoCreate Modeling 2007 und späteren Versionen ausgeliefert.
-- DerWolfgang, last updated 2007/04/05
There are several ways to do this:
*.lsp
),
then navigate to the file and open it.
If you have some Lisp code which you want CoCreate Modeling to load automatically during startup, you should place your Lisp code in one of the customization directories which CoCreate Modeling visits during startup. The choice of customization directory depends on whether you want the code to be loaded just for you, for your team, a site, or the whole company. For more details, start with the FAQ entry on automatic loading.
Da gibt es viele Wege:
*.lsp
) ändern, die Datei suchen und auswählen.
Hat man ein Stückchen Lisp-Code, das bei jedem Start automatisch von CoCreate Modeling geladen werden soll, kann man die Datei in einem der Anpassungsverzeichnisse ablegen, die CoCreate Modeling beim Start durchsucht. Welches Anpassungsverzeichnis man auswählt, hängt davon ab, ob der Code nur für einen einzelnen Anwender, eine Arbeitsgruppe, eine Firmenniederlassung oder für die ganze Firma geladen werden soll. Mehr dazu im FAQ-Eintrag zum automatischen Laden.
-- ClausBrod - 19 Nov 2006
Chances are that you are using floating-point calculations in your profile macro, and that you are running into inaccuracies which is a problem that every programmer encounters when calculating with floating-point values.
This kind of problem can be easily demonstrated by running the following two Lisp commands:
(setf foo (-1 0.01)) (display foo)
foo
will displays its value as 0.010000000000000009
in the output box - but
shouldn't that read 0.01
? How can a simple subtraction like this fail?
In fact, this is not even a CoCreate Modeling or Lisp problem. A similar subtraction will fail in CoCreate Drafting as well:
LET FOO ( 1 - (VAL '0.99')) DISPLAY (FOO > 0.01) {Result = 1}
So if both CoCreate Modeling and CoCreate Drafting fail in such a simple subtraction, maybe it's a CoCreate problem? Are their programmers too dumb to even get this right?
No. Similar code fails in other languages as well. Here's an example using
VBscript (execute the script using wscript
or cscript
):
Foo = 1 - 0.99 If Foo > 0.01 Then WScript.Echo("Foo is larger than 0.01") Else WScript.Echo("Foo is equal to or smaller than 0.01") End if
The truth is that surprises like this can happen to you in any language and in any application. The reason is that the way in which CPUs represent floating-point values is imprecise by definition - there are only a limited number of bits available to store floating-point values. A good backgrounder on this is the famous white paper What Every Computer Scientist Should Know About Floating-Point Arithmetic. Alternatively, check out the (German) article at http://www.aboutwebdesign.de/awd/content/1014916256.shtml which is less formal and good enough as an introduction for most people.
Bottom line of those articles: Calculations with floating-point values are subject to inaccuracies because their representation in computer memory has only a finite number of "digits", and sometimes you simply cannot completely avoid floating-point errors. There are, however, techniques which reduce and control the error:
-- ClausBrod
Imagine you want to replace all double-quote characters in a Lisp string
using the Integration Kit function sd-string-replace
. Seems we have a
problem here: Literal strings in Lisp start with a double-quote character,
and the next double-quote character in the string ends it. Hmmm...
The solution for this is to use so-called escape characters. In Lisp
strings, backslashes are used as escape characters. (There are
similar mechanisms in many programming languages, and the backslash
character is used suspicously often for this purpose. Is there a
secret backslash conspiracy going on here? ) Example:
(oli:sd-string-replace string "\"" "!")
This replaces all double-quote characters in string
with exclamation
marks. Note that two double-quote characters follow after the backslash.
The special meaning of the first double-quote character ("end the current
literal string") is ignored by the Lisp reader in this case because it
is preceded by an escape character.
See also the section on the Single Escape Character in the Common Lisp HyperSpec.
Nehmen wir mal an, wir wollten in einem Lisp-String alle doppelten Anführungszeichen
durch ein anderes Zeichen ersetzen, und zwar mit der Funktion sd-string-replace
aus dem Integration Kit. Das könnte problematisch werden, denn ein
Zeichenkettenliteral in Lisp beginnt mit einem doppelten Anführungszeichen,
und das nächste Anführungszeichen beendet es. Hmmm...
Die Lösung sind die sogenannten ESCAPE- oder Abdeckzeichen. In Lisp-Zeichenketten
wird der Rückstrich (Backslash) als solches Umschaltzeichen verwendet.
(In anderen Programmiersprachen gibt es ähnliche Mechanismen, und das
Backslash-Zeichen wird verdächtig oft für diesen Zweck eingesetzt -
eine Backslash-Verschwörung? ) Beispiel:
(oli:sd-string-replace string "\"" "!")
Das Kommando ersetzt alle doppelten Anführungszeichen durch Ausrufezeichen. Man beachte, daß nach dem Backslash-Zeichen zwei doppelte Anführungszeichen folgen. Die besondere Bedeutung des ersten Anführungszeichen ("beende die aktuelle literale Zeichenkette") wird von Lisp in diesem Fall ignoriert, weil ein Backslash-Zeichen vorangeht.
Siehe auch den Abschnitt Single Escape Character in der HyperSpec-Dokumentation zu Common Lisp.
-- ClausBrod
See the explanations above on escape characters to understand why the following would work:
(oli:sd-string-match-pattern-p "*\\\\*" somestring)
Hint: Four backslashes are required in the pattern string because the pattern uses a special regular expression syntax in which the backslash has a special meaning, just like in Lisp. So you need to "escape" once because of the pattern language, and then another time because of Lisp.
Siehe die Erläuterungen zum Thema Escape-Zeichen weiter oben; damit versteht man (hoffentlich), warum das folgende funktioniert:
(oli:sd-string-match-pattern-p "*\\\\*" somestring)
Hinweis: Vier Rückstriche braucht man deswegen im Muster-String, weil das Muster in einer speziellen Syntax für reguläre Ausdrücke angegeben wird, in der der Rückstrich ebenso wie in Lisp eine spezielle Bedeutung hat. Man muß also einmal wegen der regulären Ausdrücke und dann noch einmal wegen Lisp die erforderlichen Rückstriche hinzufügen.
-- ClausBrod - 13 Jan 2005
setf
and setq
?
setf
is a macro which builds on setq
, but also allows to do funky stuff like this:
(setf (fifth somelist) 42)
Note that the first argument isn't really an ordinary variable, but rather the
description (as a Lisp form) of a place where the value is to be written to. http://www.supelec.fr/docs/cltl/clm/node80.html lists which kind of forms
can be used with setf
.
In the majority of cases, this special evaluation isn't needed, so you're
probably slightly better off (in terms of performance) by using setq
.
If you get it wrong, Lisp will kindly remind you with an error message, and then
you can then still use setf
instead when required.
Historically, setf
is the abbreviation for setfq
, which,
according to
Evolution of Lisp,
stood for "quote the function and evaluate everything else".
setf
und setq
?
setf
ist ein Makro, das auf setq
aufbaut, zusätzlich aber ulkige Dinge wie dies hier
erlaubt:
(setf (fifth somelist) 42)
Das erste Argument von setf
ist keine normale Variable, sondern eher die Beschreibung
(als Lisp-Form) eines Platzes, an den der Wert geschrieben werden soll.
http://www.supelec.fr/docs/cltl/clm/node80.html listet auf, welche Arten von Lisp-Formen
bei setf
erlaubt sind.
In der Mehrzahl der Fälle braucht man solche speziellen Erweiterungen nicht,
fährt also mit setq
etwas besser (zumindest in Sachen Geschwindigkeit).
Macht man's falsch, erinnert Lisp einen ohnehin freundlicherweise in Form von
Fehlermeldungen daran, und dann kann man immer noch auf setf
umsteigen.
Aus historischer Sicht ist setf
eine Abkürzung für setfq
, was
laut Evolution of Lisp
für "quote the function and evaluate everything else" steht.
-- ClausBrod
When the Lisp interpreter loads a file, it parses and checks it for syntax problems. One such syntax problem is when you open parentheses, but forget to close then. Example:
(display "This will not work"
When saving this to a file called foo.lsp
and loading it into CoCreate Modeling,
you'll get an error message which reads like:
LISP error: Unexpected end of #<input stream "foo.lsp">.
What the Lisp interpreter is trying to say is that it arrived at the end of the file before all forms were closed properly, i.e. the number of opening parentheses does not match the number of closing parentheses. You can also run into this issue if you do not properly terminate a literal string, i.e. you forget the closing double-quote. So when you get this error message, open the Lisp file in an editor and look for missing parentheses and quotes.
A good Lisp editor will highlight matching parentheses, and also indent your code automatically so that any imbalances become readily apparent.
This error message also used to occur if the Lisp file contains a comment in the last line, and that last line does not end with a newline character. This has been fixed in CoCreate Modeling 2007.
Wenn der Lisp-Interpreter eine Datei lädt, prüft er sie auch auf Syntaxfehler. Ein solcher Syntaxfehler ist es, wenn man eine Klammer öffnet, aber sie zu schließen vergißt. Beispiel:
(display "Das klappt nicht"
Speichert man das in eine Datei namens foo.lsp
und lädt diese dann in CoCreate Modeling,
bekommt man eine Fehlermeldung wie diese:
LISP error: Unexpected end of #<input stream "foo.lsp">.
Der Lisp-Interpreter versucht hier zu sagen, daß er am Ende der Datei angekommen ist, bevor alle Lisp-Formen ordentlich geschlossen wurden, daß also die Anzahl der öffnenden Klammern nicht der Anzahl der schließenden Klammern entspricht. Das Problem kann auch auftreten, wenn man eine literale Zeichenkette nicht ordentlich abschließt, also die Gänsefüßchen am Ende vergißt. Wenn man diese Meldung bekommt, öffnet man also einfach die betreffende Datei in einem Editor und sucht nach fehlenden Klammern oder Gänsefüßchen.
Ein guter Lisp-Editor hebt automatisch zugehörige Klammernpaare hervor und rückt auch automatisch den Code ein, so daß solche Strukturfehler sofort auffallen.
Die Fehlermeldung wurde bisher auch dann angezeigt, wenn die Lisp-Datei einen Kommentar in der letzten Zeile beinhaltet und diese letzte Zeile nicht mit einem Zeilenvorschub abgeschlossen ist. Dieses Problem ist in CoCreate Modeling 2007 behoben.
-- ClausBrod - 20 April 2005, last updated 21 December 2005
SD-XXX
, I get an error message: "The function SD-XXX is undefined" First, check the spelling.
Second, all Integration Kit APIs are in the OLI
LISP package. A Lisp package is
the equivalent of a namespace in other languages. To specify the package, preprend
the function name with OLI:
, or add a use-package :oli
statement at the
beginning of your Lisp file.
(SD-XXX param1 param2) ;; package not specified, call might fail (OLI:SD-XXX param1 param2) ;; MUCH better! (use-package :OLI) ;; alternative method (SD-XXX param1 param2)
See the section on packages in the Lisp HyperSpec for more details. The introduction on packages in David Lamkins' Successful Lisp is also a good start to learn more about this topic.
Actually, in older versions of CoCreate Modeling it was sometimes to use IKIT APIs without
specifying the OLI
package. This was an undocumented side effect of our
internal code structure; it just so happened that some code
executed the required use-package
call, or at least most of the time.
Recent versions of CoCreate Modeling are less forgiving; to reduce the likelihood of
name clashes, we now enforce proper specification
of the OLI
package.
SD-XXX
aufrufe, bekomme ich eine Fehlermeldung "The function SD-XXX is undefined" Zuallererst: Korrekte Schreibweise des Kommandos überprüfen.
Zum zweiten: Alle APIs des Integration Kit befinden sich im Lisp-Package OLI
. Ein
Lisp-Package ist die Entsprechung zu Namensräumen in anderen Programmiersprachen.
Um das Package anzugeben, hängt man vor den aufzurufenden Funktionsnamen einfach
OLI:
, oder aber man benutzt das Kommando use-package :oli
am Anfang der Lisp-Datei.
(SD-XXX param1 param2) ;; Package nicht angegeben; das wird schiefgehen (OLI:SD-XXX param1 param2) ;; Viel besser! (use-package :OLI) ;; Alternative Methode (SD-XXX param1 param2)
Siehe auch den Abschnitt zu Packages in der Lisp-HyperSpec für detailliertere Erläuterungen. Die Einführung zu Packages im Buch Successful Lisp von David Lamkins ist auch ein guter Startpunkt, um mehr zu diesem Thema zu lernen.
In älteren Versionen von CoCreate Modeling konnte man übrigens manchmal straflos
IKIT-APIs ohne Angabe des Packagenamens (OLI
) aufrufen. Das war ein undokumentierter
Seiteneffekt der internen Codestruktur; zufälligerweise benutzte interner Code
den passenden Aufruf von use-package
und nahm diese Anmeldung nicht zurück.
Neuere Versionen von CoCreate Modeling sind weniger nachsichtig in diesem Punkt. Um die
Wahrscheinlichkeit von Namenskollisionen zu reduzieren, erzwingt CoCreate Modeling seit einiger
Zeit die korrekte Angabe des Packagenamens.
-- ClausBrod
In the example displayed here, a function is called which expects a parameter of type
double
, but instead is passed a structure of type GPNTDOCU
. So this type of error
message usually indicates a programming error (incorrect parameter passing)
in the Lisp code which has been executed.
As you can see from the screenshot, the error message itself is slightly buggy, too .-)
Im Beispiel wird eine Funktion aufgerufen, die einen Parameter vom Typ double
erwartet,
stattdessen aber vom Aufrufer eine Struktur vom Typ GPNTDOCU
erhält. Diese Art von
Fehlermeldung deutet also auf einen Programmierfehler (falsche Parameterübergabe)
im Lisp-Code hin, der gerade ausgeführt wurde.
Wie man dem Bild entnehmen kann, ist allerdings die Fehlermeldung selbst auch nicht ganz fehlerfrei .-)
-- ClausBrod
If you only used the official APIs in the Integration Kit, there should rarely be a need to port anything. Almost all of them are cross-platform.
However, there are exceptions. One such exception is when you use sd-sys-background-job
or sd-sys-exec
to execute external commands.
Such code will only continue to work if the external commands are
available on the Windows platform as well.
In some cases, the HP-UX code will try to execute UNIX shell commands, such as grep
,
awk
, sort
, ls
etc etc. For many external commands, you will actually find
equivalent Integration Kit APIs or Lisp commands, which is the clearly preferable
implementation. For instance, rather than using cp
as an external command, use
the sd-copy-file
API; and to create a directory, sd-make-directory
is more
portable than mkdir
. Consult the "Filing and Operating System" section of
the Integration Kit documentation for details. Lisp also has a number of
system-level commands, such as to access files, so the Common Lisp HyperSpec is
also a good place to start your search.
Sometimes, however, you will still have to use external commands. The good news
is that the DOS batch language (which can be used in sd-sys-exec
commands
on Windows) is actually quite flexible and powerful, even though the syntax differs
significantly from UNIX systems. For example, grep
can almost always be replaced
by findstr
, rm
is the same as del
, dir
matches ls
most of the time etc.
A good book on the subject is Windows NT Shell Scripting by Timothy Hill. Also, there are many sources in the Internet which discuss batch file programming, such as Rob van der Woude's Scripting Pages.
Yet another alternative is to use one of the UNIX-lookalike tool collections
and shell environments out there. These allow to continue to use grep
, ksh
and friends, so instead of porting your macros, you simply install a UNIX
shell environment on your systems.
There are both commercial and free implementations. Examples:
Solange man nur die offiziellen APIs im Integration Kit verwendet, sollte es selten überhaupt einen Bedarf geben, irgendetwas zu portieren. Fast alle dieser APIs sind für alle Plattformen gültig.
Es gibt aber Ausnahmen. Eine solche Ausnahme ist es, wenn man sd-sys-background-job
oder sd-sys-exec
zum Ausführen externer Kommandos verwendet. Solcher Programmcode
wird nur dann auf der neuen Plattform (in unserem Beispiel Windows) weiter funktionieren,
wenn die externen Kommandos dort ebenfalls verfügbar sind.
In einigen Fällen versuchen HP-UX-Makros, UNIX-Kommandos auszuführen,
beispielsweise grep
, awk
, sort
oder ls
. Für viele solcher externen Kommandos
kann man übrigens Entsprechungen in Lisp selbst oder im Integration Kit finden -
ganz klar ist das einer plattformabhängigen Programmierung vorzuziehen.
Beispielsweise kann man statt cp
als externem Kommando einfach sd-copy-file
verwenden; zum Anlegen eines Verzeichnisses ist sd-make-directory
portabler
als mkdir
. Der Abschnitt "Filing and Operating System" in der Dokumentation
zum Integration Kit ist hier besonders interessant. Lisp stellt ebenfalls
eine Reihe von Kommandos zur Verfügung, die von der verwendeten Plattform
abstrahieren, beispielsweise zum Zugriff auf Dateien - die HyperSpec-Dokumentation
zu Common Lisp ist also auch hier ein guter Anlaufpunkt.
Manchmal muß man aber doch auf externe Kommandos ausweichen.
Die gute Nachricht ist hier, daß die Batch-Sprache von DOS (die
man für mit sd-sys-exec
ausgeführte Kommandos einsetzen kann)
recht flexibel und vielseitig ist, auch wenn die Syntax doch oft erheblich
von UNIX-Systemen abweicht. Beispielsweise kann man grep
fast immer durch
findstr
ersetzen; rm
ist fast identisch mit del
, und dir
entspricht meistens
ls
. Ein gutes Buch zu diesem Thema ist
Windows NT Shell Scripting
von Timothy Hill. Es gibt auch viele weitere Quellen im Internet, die Batch-Programmierung
behandeln, beispielsweise die Scripting-Seiten von Rob van der Woude.
Eine weitere Alternative sind UNIX-ähnliche Werkzeugsammlungen
und Shell-Umgebungen, die es erlauben, wie gewohnt grep
, ksh
und Kumpane zu verwenden. Anstatt also die Makros zu portieren, installiert
man einfach eine solche Shell-Umgebung auf den Zielsystemen.
Es gibt sowohl kommerzielle als auch freie Implementierungen. Beispiele:
-- ClausBrod, last update 2007-04-03
The IKIT function sd-execute-annotator-command
is a convenient way to do
this. For example, if you have an OSDD macro which takes two parameters,
you can call it like this:
(oli:sd-execute-annotator-command :cmd (format nil "my_osdd_macro ~A ~A" param1 param2))
Note how format
is used to build the full macro string before passing
it to Annotator.
Das geht recht bequem über die IKIT-Funktion sd-execute-annotator-command
.
Wenn man zum Beispiel ein OSDD-Makro hat, das zwei Parameter erwartet, kann man
es wie folgt rufen:
(oli:sd-execute-annotator-command :cmd (format nil "my_osdd_macro ~A ~A" param1 param2))
Man beachte, wie hier format
benutzt wird, um den Makroaufruf
aufzubauen, bevor man ihn an Annotator schickt.
-- ClausBrod - 11 Jun 2005