Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

macro characters

5 views
Skip to first unread message

Stephane Paris

unread,
Dec 5, 1997, 3:00:00 AM12/5/97
to

Hi,

Can someone tell me how to define the macro characters #\[, #\]
so that they give the following automatic translation into list

[ 1 2 3 4 ] ====> ( 1 2 3 4 )

This probably can be in an easy way...
But, the following function bugs !

======================================================================
( defun opening (s char)

(declare (ignore char))

(do
(
( ch (peek-char t s t nil t)
(peek-char t s t nil t) )
( liste nil )
)

(
( char= ch #\] )
( read-char s t nil t )
( reverse liste )
)

(let
(
( item (read-preserving-whitespace s t nil t) )
)

(push item liste)

) ;; let

) ;; do

) ;; opening


( Set-Macro-Character #\[ #'opening )
( Set-Macro-Character #\] ( Get-Macro-Character #\) ) )

======================================================================


thanks in advance for all helps.

stephane paris.

Kent M Pitman

unread,
Dec 5, 1997, 3:00:00 AM12/5/97
to

Stephane Paris <pa...@lrim.univ-metz.fr> writes:

> Can someone tell me how to define the macro characters #\[, #\]
> so that they give the following automatic translation into list
>
> [ 1 2 3 4 ] ====> ( 1 2 3 4 )
>
> This probably can be in an easy way...
> But, the following function bugs !

You're probably better off not to try to do (get-macro-character #\)).
Many implementations deviate from the standard on ( and ) because it's
more efficient. Try defining ] as a single-character token.

(defun single-char-macro (stream char)
(declare (ignore stream))
char)

(set-macro-character #\] 'single-char-macro)

This change to the setup of #\] makes the rest of your code work for me.

By the way, some style notes:

- I don't recommend putting open and close parens on separate
lines. It's not what most Lisp programmers do, and it means even the
smallest of Lisp programs will fill your screen and make you have to
scroll your screen to read (as this one did to me as I debugged it).

- There's generally not an efficiency penalty to using LET even when
the variable will be used only once, as in:
(let ((item (read-preserving-whitespace s t nil t)))
(push item liste))
and sometimes it's useful to make a LET binding to name a intermediate
quantity you plan to use only once (e.g., for self-documentation purposes)
but ITEM is not a very informative name, and Lisp is an expression-oriented
language, so I recommend just:
(push (read-preserving-whitespace s t nil t) liste)

- Since the list LISTE is freshly consed, you should use NREVERSE, not REVERSE,
at the end of the loop since you don't need a whole new set of conses
for the result--you're about to discard them anyway. NREVERSE will reuse
those same conses and the READ will not then make spurious additional structure.

As an aside, you haven't written any code for handling "." and I don't
know if you want to. This particular function you're writing is one of the
only chances you're likely to ever get to use the function NRECONC, by the way.
It's the right function (instead of NREVERSE) for putting the dotted component
onto the end of a dotted list. :-)

Good luck.


Chuck Fry

unread,
Dec 5, 1997, 3:00:00 AM12/5/97
to

In article <sfwu3cn...@world.std.com>,

Kent M Pitman <pit...@world.std.com> wrote:
>By the way, some style notes:
>
> - I don't recommend putting open and close parens on separate
> lines. It's not what most Lisp programmers do, and it means even the
> smallest of Lisp programs will fill your screen and make you have to
> scroll your screen to read (as this one did to me as I debugged it).

Hi Kent. I beg to differ with this point. Of all the nits you picked
in the original poster's code, this is probably the least significant.

The style you recommend is fine when you know your code is mostly stable
as it stands. For code under active development by multiple
programmers, I prefer leaving the trailing ) of PROGN-like constructs
and some multi-line function calls on a separate line.

Why? Because sometimes during development there's a need to comment out
a form in one of these contexts. If the trailing ) of the containing
form is on the same line, you then have to add another trailing paren,
and Emacs complains. Or the programmer commenting out the code fails to
notice the trailing paren, and now you have paren mismatches that will
kill the compiler and take a while to track down.

I agree that putting the trailing paren on a separate line takes up more
screen space and makes the code look bloated, but sometimes the tradeoff
is worth that minor inconvenience. Is anyone still using 24-line
displays?? I suspect not.

Also remember that there's no accounting for taste.

-- Chuck
--
Chuck Fry -- Jack of all trades, master of none
chu...@chucko.com (text only please), chuc...@home.com (MIME enabled)
This space for rent... NOT.

Kent M Pitman

unread,
Dec 5, 1997, 3:00:00 AM12/5/97
to

chu...@best.com (Chuck Fry) writes:

> The style you recommend is fine when you know your code is mostly stable
> as it stands. For code under active development by multiple
> programmers, I prefer leaving the trailing ) of PROGN-like constructs
> and some multi-line function calls on a separate line.

I've done this myself with long bodies and lists with changing
elements. But the code in question was much more verbose than this in
terms of its paren separation and way far from any natural indentation
I've seen in even the most "changing" of programs. It ran onto multiple
screens only because of its airy line-breaking to accomodate parens
noting their other end.

THIS PROGRAM:

( defun opening (s char)

(declare (ignore char))

(do
(
( ch (peek-char t s t nil t)
(peek-char t s t nil t) )
( liste nil )
)

(
( char= ch #\] )
( read-char s t nil t )
( reverse liste )
)

(let
(
( item (read-preserving-whitespace s t nil t) )
)

(push item liste)

) ;; let

) ;; do

)

SHOULD (IN MY OPINION) BE WRITTEN:

(defun opening (s char)
(declare (ignore char))
(do ((ch (peek-char t s t nil t)


(peek-char t s t nil t))
(liste nil))
((char= ch #\])
(read-char s t nil t)
(reverse liste))

(let ((item (read-preserving-whitespace s t nil t)))

(push item liste))))

so that it fits easily on even a modest-size screen and can
be examined as a whole. I do agree that in the case of rapid
change, some or all of the hanging parens shown here might be
appropriate for a limited time during development:

(defun opening (s char)
(declare (ignore char))
(do ((ch (peek-char t s t nil t)


(peek-char t s t nil t))
(liste nil)
)
((char= ch #\])
(read-char s t nil t)
(reverse liste)
)

(let ((item (read-preserving-whitespace s t nil t))
)
(push item liste)

)))

when things are changing a lot. But the parens are not there
because they are pretty there, they are there because they acknowledge
a potential for change at those points. When you don't think there
will be change, I recommend moving them to the end of the previous line
since they don't add information and they just steal vertical space
in the editor.

Also, having recently worked with a large body of such code from a
customer, I can tell you another reason for not doing the

) ;matches do
) ;matches if
);matches defun

thing is that sometimes an if becomes a when or whatever and it greatly
slows editing to have to go update all these comments which contain
redundant information about what is being closed when Control-Meta-B in
a good Emacs-like editor will give you the same info.

But like all style rules, they may need to be broken if you have other
more compelling reasons. The purpose of style is not to be dogmatic,
it's to be practical. And you can't best apply any style rule without
knowing WHY you are applying it since you have to know when to be willing
to bend or break it.

William Paul Vrotney

unread,
Dec 6, 1997, 3:00:00 AM12/6/97
to

In article <669p4f$krc$1...@shell5.ba.best.com> chu...@best.com (Chuck Fry)
writes:

> >
> > - I don't recommend putting open and close parens on separate
> > lines. It's not what most Lisp programmers do, and it means even the
> > smallest of Lisp programs will fill your screen and make you have to
> > scroll your screen to read (as this one did to me as I debugged it).
>
> Hi Kent. I beg to differ with this point. Of all the nits you picked
> in the original poster's code, this is probably the least significant.

I agree with Kent on this and beg to differ with you.

>
> The style you recommend is fine when you know your code is mostly stable
> as it stands. For code under active development by multiple
> programmers, I prefer leaving the trailing ) of PROGN-like constructs
> and some multi-line function calls on a separate line.
>

I use the style Kent alludes to with unstable code as well and have never
have any of the problems you site, but then again I use Emacs.

> Why? Because sometimes during development there's a need to comment out
> a form in one of these contexts. If the trailing ) of the containing
> form is on the same line, you then have to add another trailing paren,
> and Emacs complains. Or the programmer commenting out the code fails to
> notice the trailing paren, and now you have paren mismatches that will
> kill the compiler and take a while to track down.
>

Are you using Emacs? Also if you are using Common Lisp do you know about
balanced comments (#| |#). With balanced comments there is no need to put
those parentheses on separate lines. Also if you *are* using Emacs and
Common Lisp here is a simple Emacs function to help you with inserting
balanced comments around expressions:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-key lisp-mode-map "\C-c;" 'cl:insert-balanced-comment)

(defun cl:insert-balanced-comment (arg)
"Insert a balanced comment with point inside.
ARG = C-u = place comment around region.
ARG > 0 = place comment around next ARG s-expressions."
(interactive "P")
(ut:insert-balanced-comment arg "#|" "|#"))

; Insert a balanced comment (cleft cright) with point inside.
; ARG = C-u = place comment around region.
; ARG > 0 = place comment around next ARG s-expressions.
(defun ut:insert-balanced-comment (arg cleft cright)
(cond ((not arg)
(insert cleft) (insert cright) (backward-char (length cright)))
((not (numberp arg))
(let ((begin (region-beginning)) (end (region-end)))
(goto-char begin) (insert cleft)
(goto-char (+ end 2)) (insert cright)))
(t (cond ((< arg 0) (setq arg (- arg)) (backward-sexp arg)))
(insert cleft) (forward-sexp arg) (insert cright))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


Note that this does not provide a way to uncomment the expression. I
generally use s-expression operators for that. But if someone really wants
an uncomment balanced comment I can supply that as well.
--

William P. Vrotney - vro...@netcom.com

Kent M Pitman

unread,
Dec 6, 1997, 3:00:00 AM12/6/97
to

vro...@netcom.com (William Paul Vrotney) writes:

> Are you using Emacs? Also if you are using Common Lisp do you know about
> balanced comments (#| |#).

While on the subject of style (and risking someone will chime in to disagree
further :-), here's a style tip about #|...|#.

Many text editors treat |...| like a string for reasons that can trace their
roots to Teco-based Emacs for Maclisp on ITS in the late 1970's. Even so,
the fact is that they don't do good paren balancing while inside |...| so if
you really are using the nested feature, I strongly recommend this kludge:
#||...||# for code
#|...|# for text
The cool thing about #||...||# is that the innermost pair of |'s is in the
comment and hurts nothing from the point of view of CL, but from the point of
view of Emacs, the || in #|| or in ||# will appear as a balanced set, and so
you'll still get nice paren balancing while within #||...||# since Emacs will
not know you are "in" something. But if you're commenting random text, still
using #|...|# is good. e.g.,

#| There are three reasons for this:
a) something
b) something else
c) something else again
|#

In that case, Emacs will not regard these as "unbalanced parens". But for
code:

#|| ;No longer used
(defun foo (x y)
(+ x y))
||#


Erik Naggum

unread,
Dec 6, 1997, 3:00:00 AM12/6/97
to

* Chuck Fry

| The style you recommend is fine when you know your code is mostly stable
| as it stands. For code under active development by multiple programmers,
| I prefer leaving the trailing ) of PROGN-like constructs and some
| multi-line function calls on a separate line.
|
| Why? Because sometimes during development there's a need to comment out
| a form in one of these contexts. If the trailing ) of the containing
| form is on the same line, you then have to add another trailing paren,
| and Emacs complains.

if you use Emacs, skipping the whole form to insert a newline is a piece of
cake. also, if you have `comment-region' bound to a key (I use C-;), you
can mark the whole sexp with `mark-sexp', normally bound to M-C-@ and
M-C-SPC, comment out the region, exchange point and mark, insert a newline,
and that's about it. M-C-@ C-2 C-; C-x C-x C-j

on the other hand, if you know you're going to comment out a region, you're
much better off with the nesting comment syntax: #| ... |#. since this
ends with the |#, not with the end of the line, M-C-@ #| C-x C-x |# will
have commented out a sexp. I much prefer this comment style wherever it is
available, and implemented it for Emacs Lisp, too. (it never got into the
distribution, however.)

| Also remember that there's no accounting for taste.

it's also curious to watch people rationalize their styles by blaming their
tools...

that said, I find excessive whitespace around parentheses in any language
_very_ disturbing. in particular, whitespace _after_ an open paren or
bracket and _before_ a close paren or bracket bothers me enough to (want
to) fix it before I proceed to (try to) read the code. indeed, whitespace
can increase the importance of the trivial and unimportant just like lack
of whitespace can hide and obscure the important.

whitespace is a profoundly powerful tool when communicating with the human
reader of source code -- so I tend to think that people who don't
understand the importance of whitespace cannot have understood much else,
either. this negative view is of course only exacerbated by the huge heaps
of really bad code one comes across with whitespace abuse in it, too.

#\Erik
--
if you think this year is "97", _you_ are not "year 2000 compliant".

see http://sourcery.naggum.no/emacs/ for GNU Emacs 20-related material.

Georg Bauer

unread,
Dec 6, 1997, 3:00:00 AM12/6/97
to

Kent M Pitman <pit...@world.std.com> wrote:

> SHOULD (IN MY OPINION) BE WRITTEN:

I fully agree. Hanging brackets are awfull. They give you _no_
additional information but take up more space. So why should you
possibly do that?

Uncommenting expressions can more easily be done by putting a #+BLA
directly in front of the expression - supposed that BLA is no defined
feature, the expression is removed. Another plus of this: you can drop
out some code by using BLAX, BLAY and such and so can selectivly enable
them just by changing *features* - without changing your code. Helps
much with development and goes much better with the typical Lisp
structure.

bye, Georg

Philip Lijnzaad

unread,
Dec 8, 1997, 3:00:00 AM12/8/97
to

chu...@best.com (Chuck Fry) writes:

> Why? Because sometimes during development there's a need to comment out
> a form in one of these contexts. If the trailing ) of the containing
> form is on the same line, you then have to add another trailing paren,

> and Emacs complains. Or the programmer commenting out the code fails to
> notice the trailing paren, and now you have paren mismatches that will
> kill the compiler and take a while to track down.

Another, (probably bad) suggestion would be to roll your own `matching
comments': using a conditional:

Replacing

(progn (do-this)
(maybe-do-that 42)
(and-maybe-this 'too)
(do-that foo))

by

(progn (do-this)
(and nil (maybe-do-that 42)
(and-maybe-this 'too))
(do-that foo))

It's slow, and visually not too obvious, but might just be useful in some
cases.

Philip


--
"It's just that I get up 20 hours earlier than everybody else"
Philip Lijnzaad, lijn...@ebi.ac.uk | European Bioinformatics Institute
+44 (0)1223 49 4639 | Wellcome Trust Genome Campus, Hinxton
+44 (0)1223 49 4468 (fax) | Cambridge CB10 1SD, GREAT BRITAIN
PGP fingerprint: E1 03 BF 80 94 61 B6 FC 50 3D 1F 64 40 75 FB 53

Kent M Pitman

unread,
Dec 8, 1997, 3:00:00 AM12/8/97
to

Georg...@muensterland.org (Georg Bauer) writes:

Well, just be careful with what features you use. My vague
recollection is that some clever jokester at Harlequin got caught
using #+Lucid conditionals (figuring the likelihood of our proprietary
code every getting to Lucid or vice versa was zero) that were tripped
up when Harlequin rescued what was then Lucid Common Lisp (now Liquid
Common Lisp) from the failing Lucid Inc. and started merging parts of
its code with our own. The feature system may sometimes surprise you
with what features turn out to be true, especially if your code is
longer-lived than you expect. It was NOT intended for commenting
things out.

I recommend if you do use it, you use something nice and obvious like
#+ignore or #+comment, which are about the only two names I've ever seen
that make sense to me.

Now if you're being careful to attach real semantics to things,
tagging may be perfectly fine, as in your BLAX and BLAY example. But
don't just make up nonsense words and assume they'll never be enabled.
It's just a risk someone else will see your nonsense word as a
Bizarre Lisp Acronym and will turn it on without realizing.


Georg Bauer

unread,
Dec 9, 1997, 3:00:00 AM12/9/97
to

Kent M Pitman <pit...@world.std.com> wrote:

> I recommend if you do use it, you use something nice and obvious like
> #+ignore or #+comment, which are about the only two names I've ever seen
> that make sense to me.

Normally I use #+xxxx or #+aaaa (they are easy to spot in the code) and
after debugging-session finishes, I remove them. No use to leave
temporary markers in the source. It's mainly to avoid heavy reediting if
I try out different designs. After I get a clue on what I am doing
(happens seldom enough), I straighten the source.

bye, Georg

William Paul Vrotney

unread,
Dec 10, 1997, 3:00:00 AM12/10/97
to

As Jacques Duthen has so kindly pointed out, the Emacs code that I posted
had an error in the common ut:insert-balanced-comment part of the code for
the C-U argument handling (see below) in the event that you change the
lengths of the left and right comment delimiters.

You need to replace (+ end 2) by (+ end (length cleft))

Also, notice that it should also have the comment

; ARG < 0 = place comment around previous ARG s-expressions.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


(defun cl:insert-balanced-comment (arg)
"Insert a balanced comment with point inside.
ARG = C-u = place comment around region.
ARG > 0 = place comment around next ARG s-expressions."
(interactive "P")
(ut:insert-balanced-comment arg "#|" "|#"))

; Insert a balanced comment (cleft cright) with point inside.
; ARG = C-u = place comment around region.
; ARG > 0 = place comment around next ARG s-expressions.
(defun ut:insert-balanced-comment (arg cleft cright)
(cond ((not arg)
(insert cleft) (insert cright) (backward-char (length cright)))
((not (numberp arg))
(let ((begin (region-beginning)) (end (region-end)))
(goto-char begin) (insert cleft)
(goto-char (+ end 2)) (insert cright)))
(t (cond ((< arg 0) (setq arg (- arg)) (backward-sexp arg)))
(insert cleft) (forward-sexp arg) (insert cright))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

--

0 new messages