lisp/cedet/semantic/wisentThen inside wisent there should be a number of .wy files. Just download such a version of cedet, unzip it and remember the name of the folder. No need to install anything right now. We shall use
load-file
as an when necessary.
line : NUM line : line NUMHere the terminal NUM denotes a number, and the nonterminal line, as you can see from the grammar itself, is just a list of a positive number of NUM's. Just to give a purpose to this we shall try to find the sum of all the numbers.
( |
|
(number)
| 1 |
() | 2 |
(line | 3 |
( (number) (string-to-number $1) )
| 4 |
( (line number) (+ $1 (string-to-number $2) )
)
)
| 5 |
Explanation of the code:
(setq g
'((number) () (line ( (number) (string-to-number $1))
( (line number) (+ $1
(string-to-number $2)))))
)
Don't forget the little single quote character just before the
grammar. It prevents lisp from trying to evaluate the grammar
list.
M-x
load-file.
Let's apply wisent-grammar-compile:
(setq p (wisent-compile-grammar g))The action and goto tables (plus sundry other relevant pieces of information) are stored in lisp format inside the variable
p. If you type p in the buffer
and simply hit C-x C-e you'll see the value
of p in the minibuffer. Not that it will help to
look at it, but you get some satisfaction
that wisent-compile-grammar is doing something!
Well, that takes care of the parser. Now we need a lexer to feed
inputs to the parser.
define-lex function that comes with
semantic-mode. Issue M-x semantic-mode
for this.
(define-lex lx "" semantic-lex-ignore-newline semantic-lex-ignore-whitespace semantic-lex-number semantic-lex-default-action)Eventually we are going to use the function
semantic-lex-buffer, which will make use of
the lx that we created just now. The question is how
do we pass lx to semantic-lex-buffer?
The technique is to use a global
variable semantic-lex-analyzer:
(setq semantic-lex-analyzer 'lx)Now, emacs has the concept of a syntax table that tells it about the category of each character in a buffer. While doing lexical analysis emacs allows you the luxury of using any syntax table of our choice. This allows analysing a buffer in a way other than what its current mode dictates. So we need to specify the syntax table:
(setq semantic-lex-syntax-table (standard-syntax-table))Now we are all set and can apply
semantic-lex-buffer
to extract a sequence of tokens. We want to save this sequence in
a variable where wisent can find it.
(setq wisent-lex-istream (semantic-lex-buffer))Finally we have to do the parsing:
(wisent-parse p 'wisent-lex)Here
wisent-lex is a built-in function that reads
the tokens one by one from the
variable wisent-lex-istream that we created just
now.
The wisent-parse function will return the attribute
associated with the start symbol. Thus, in our example, the
return value is the sum, which we can pretty-print like this:
(insert (format "Total is %s\n" (wisent-parse p 'wisent-lex))))Nothing complicated so far! Now we encounter a little difficulty. We have made use of different global variables to interface our code with existing wisent code. All these global variables are what emacs calls buffer local, which means each buffer has its own copies of these variables. Even if you use
setq to change the value the changes are not
visible in a different buffer. Let's understand why this is going
to pose a difficulty for us. We want to parse a buffer. Call it
the target buffer. Our compiler code will reside in
another buffer (compiler buffer, say). So all the
above setq's will be inside the compiler
buffer. The moment you visit the target buffer to
start the parsing, all the globals will forget the values that
you
setq-ed into them in the compiler buffer! So
it looks like we need to have the setq's inside
the target buffer. But that does not look good either: that
buffer should just contain the stuff that we want to parse.
The solution to this dilemma utilises a behaviour of emacs: If you call a function
while visiting a buffer, and that function sets the value of a
buffer local variable, then the new value remains visible in that
buffer. So we must pack all our setq's that deal
with the buffer local variables, into a function, and call that
function (interactively) from the target buffer:
(defun doparse () (interactive) (setq semantic-lex-analyzer 'lx) (setq semantic-lex-syntax-table (standard-syntax-table)) (setq wisent-lex-istream (semantic-lex-buffer)) (insert (format "Total is %s\n" (wisent-parse p 'wisent-lex))))Now we are all set. Create a buffer containing a list of numbers like
34 3.9 -89Visit that buffer, and issue the command
M-x
doparse. You will immediately see the output: "Total is
-51.1" written where your cursor is.
wisent-parse. If your requirement is not very
exotic, then you might be better off to allow semantic to work
with your parser. Semantic already has built-in tools for various
useful activities like tag completion, tag highlighting etc.