Problem with lexical analyser in scm.el

Rupert Swarbrick <[email protected]> Wed, 29 Jul 2015 17:38:59 +0100
Newsgroups gmane.emacs.cedet
Message-ID <[email protected]>
In the current version of cedet/semantic/bovine/scm.el, we have the
following:

  ;; Note: Analyzer from Henry S. Thompson
  (define-lex-regex-analyzer semantic-lex-scheme-symbol
    "Detect and create symbol and keyword tokens."
    "\\(\\sw\\([:]\\|\\sw\\|\\s_\\)*\\)"
    ;; (message (format "symbol: %s" (match-string 0)))
    (semantic-lex-push-token
     (semantic-lex-token
      (or (semantic-lex-keyword-p (match-string 0)) 'symbol)
      (match-beginning 0) (match-end 0))))

If you have something like the following:

  (define (/foo arguments)
    (write "Hello"))

then semantic dies with an error when trying to parse the file. The
regular expression doesn't match because the forward slash symbol has
syntax class _ ("symbol") in Scheme mode (and would need to have syntax
class "w"). Another problem with the regex is that it matches a name
like 0foo, which I don't think it should do.

I see there's a formal syntax in "The Scheme Programming Language, 4th
edition", which you can find at:

  http://www.scheme.com/tspl4d/grammar.html

Matching that with a regex seems a bit difficult but I came up with the
following, which appears to work:

  (defun semantic-lex-scheme-identifier-at-point (&optional bound)
    "Returns a pair (START . END) if there is a valid Scheme
  identifier at point. Returns nil otherwise."
    ;; This tries to follow the formal semantics given in The Scheme Programming
    ;; Language, 4th ed.
    (let ((initial-re "[a-zA-Z!$%&*/:<=>?~_^]")
          (subsequent-re "[a-zA-Z!$%&*/:<=>?~_^0-9.+-@]"))
      (when (or (looking-at initial-re)
                (member (get-char-code-property (char-after)
                                                'general-category)
                        '("Lu" "Ll" "Lt" "Lm" "Lo" "Mn" "Nl" "No"
                          "Pd" "Pc" "Po" "Sc" "Sm" "Sk" "So" "Co")))
        (cons (point)
              (save-excursion
                (while (or (looking-at subsequent-re)
                           (member (get-char-code-property (char-after)
                                                           'general-category)
                                   '("Lu" "Ll" "Lt" "Lm" "Lo" "Mn" "Nl" "No"
                                     "Pd" "Pc" "Po" "Sc" "Sm" "Sk" "So" "Co"
                                     "Nd" "Mc" "Me")))
                  (forward-char))
                (point))))))

  (define-lex-analyzer semantic-lex-scheme-symbol
    "Detect and create Scheme symbol and keyword tokens."
    ;; Since semantic-lex-scheme-identifier-at-point doesn't set up match-data,
    ;; it's a bit of a faff to use the framework in define-lex-analyzer if we
    ;; don't want to have to call the function twice. So we cheat and set an
    ;; "always true" condition, then conditionally push tokens ourselves.
    (let ((bounds (semantic-lex-scheme-identifier-at-point)))
      (when bounds
        (semantic-lex-push-token
         (semantic-lex-token
          (or (semantic-lex-keyword-p
               (buffer-substring (car bounds) (cdr bounds)))
              'symbol)
          (car bounds) (cdr bounds))))))


Could we replace the existing lexical analyzer with this or something
similar? I have a copyright assignment on file for Emacs if that's
relevant.


Thanks,

Rupert

------------------------------------------------------------------------------