Ответ 1
Вы уже знакомы с рекурсивными анализаторами спуска? Их относительно легко написать вручную на вашем любимом языке программирования, который будет включать Emacs Lisp. Для очень простого синтаксического анализа вы часто можете использовать looking-at
и search-forward
. Они также легли бы в основу любой токенизации подпрограмм, которые будут вызываться парсером рекурсивного спуска или любым другим стилем парсера.
[11 февраля 2009] Я добавил пример рекурсивного парсера спуска в emacs lisp ниже. Он анализирует простые арифметические выражения, включая сложение, вычитание, умножение, деление, возведение в степень и выраженные в скобках подвыражения. В настоящий момент предполагается, что все токены находятся в глобальной переменной *tokens*
, но если вы измените gettok
и peektok
по мере необходимости, вы можете пройти через буфер. Чтобы использовать его как есть, просто попробуйте следующее:
(setq *token* '( 3 ^ 5 ^ 7 + 5 * 3 + 7 / 11))
(rdh/expr)
=> (+ (+ (^ 3 (^ 5 7)) (* 5 3)) (/ 7 11))
Далее следует код анализа.
(defun gettok ()
(and *token* (pop *token*)))
(defun peektok ()
(and *token* (car *token*)))
(defun rdh/expr ()
(rdh/expr-tail (rdh/factor)))
(defun rdh/expr-tail (expr)
(let ((tok (peektok)))
(cond ((or (null tok)
(equal tok ")"))
expr)
((member tok '(+ -))
(gettok)
(let ((fac (rdh/factor)))
(rdh/expr-tail (list tok expr fac))))
(t (error "bad expr")))))
(defun rdh/factor ()
(rdh/factor-tail (rdh/term)))
(defun rdh/factor-tail (fac)
(let ((tok (peektok)))
(cond ((or (null tok)
(member tok '(")" + -)))
fac)
((member tok '(* /))
(gettok)
(let ((term (rdh/term)))
(rdh/factor-tail (list tok fac term))))
(t (error "bad factor")))))
(defun rdh/term ()
(let* ((prim (rdh/prim))
(tok (peektok)))
(cond ((or (null tok)
(member tok '(")" + - / *)))
prim)
((equal tok '^)
(gettok)
(list tok prim (rdh/term)))
(t (error "bad term")))))
(defun rdh/prim ()
(let ((tok (gettok)))
(cond ((numberp tok) tok)
((equal tok "(")
(let* ((expr (rdh/expr))
(tok (peektok)))
(if (not (equal tok ")"))
(error "bad parenthesized expr")
(gettok)
expr)))
(t (error "bad prim")))))