-- Trey <trey(a)veggie.stu.wesleyan.edu> spake thusly:
1. Where would one suggest looking to learn better how
parse-partial-sexp works? In my opinion, that section of the elisp
reference manual is too short. In my hunting through the
xemacs-packages, I found many examples of parse-partial-sexp in use,
but was never able to properly understand what was going on.
I've been doing a lot of work with this one lately, so I may be able to
help here. `parse-partial-sexp' is the primary tool used for parsing
syntax in (X)Emacs. It's actually useful for more than just Lisp
syntax. It can parse over any well-formed balanced expressions (C, C++,
etc.), and is used by such things as font-lock to do syntax parsing. It
works like this:
(parse-partial-sexp from to &optional targetdepth stopbefore oldstate
commentstop buffer)
It parses a file from <from> and stops at <to> (or possibly before). It
returns a list which indicates the state of the file at the point it
stopped at (ie, point). I won't detail each element of the returned
state (do '(describe-function "parse-partial-sexp")' for details), but
the basic information is:
- The depth of parentheses-like expressions (determined by (),{},[],
etc.) as defined by the buffer's syntax table.
- Whether or not point is inside a comment or string.
- The address of various things (start of innermost balanced
expression, start of containing comment/string if relevant).
You can also get parse-partial-sexp to stop at specific places (other
than <stop>) if desired by setting the inputs:
- targetdepth (intgeger): cause parsing to stop as soon as that depth
of balances expressions is reached
- stopbefore (t): stop before the beginning of a paren-like opener.
- commentstop (t): stop at the start of a comment
- commentstop ('syntax-table): stop at the start of a comment or
string, or after the end of a comment or string
If you want to continue parsing, the proper thing to do is call
`parse-partial-sexp' again from the point it stopped and pass the
previously returned state as <oldstate>.
As for how to use it, it depends on what you're trying to get. You can
get the syntax state of a particular position in a buffer by calling
"(parse-partial-sexp (point-min) (point))". The returned list would
tell you how deep that point is, and whether it's in a comment or
string. For instance, the beginning-of-defun that I just rewrote does
something like:
(let* ((state (parse-partial-sexp (point-min) (point)))
(depth (nth 0 state))
(pt (if (or (nth 3 state) (nth 4 state))
(nth 8 state)
(point))))
(if (> depth 0)
(goto-char (scan-lists pt -1 depth)))
This gets the current syntax state, figures out the beginning of the
enclosing comment or string if there is one, and then uses scan-lists
to
jump to the beginning of the outermost enclosing sexp (balanced
parentheses).
`font-lock-fontify-syntactically-region' uses `parse-partial-sexp' to
scan the region, stopping at the beginning and end of each comment and
string, and uses the information returned to fontify said comments and
strings.
I also suggest reading up on syntax tables:
M-: (Info-goto-node "(lispref)Syntax Tables")
`parse-partial-sexp' uses these to determine syntax of characters when
parsing. Understanding syntax tables is important for understanding how
`parse-partial-sexp' works.
Hope this helps. Let me know if you have any further questions.