Commit a9128931 authored by Luke Lee's avatar Luke Lee
Browse files

Aggregate hideif parser enhancements for a complete supporting of C/C++

expressions and operator precedence. Also apply code review changes.

* lisp/progmodes/hideif.el : Related enhancements.
parent 6affb4a8
2014-01-28 Luke Lee <luke.yx.lee@gmail.com>
* progmodes/hideif.el: Extend to full CPP expression syntax.
(hif-token-alist): Add missing tokens.
(hif-token-regexp): Add support for float/octal/hex immediates.
(hif-string-literal-regexp): New const.
(hif-tokenize): Recognize strings and float/octal/hex immediates.
(hif-exprlist): New function.
(hif-parse-if-exp): Use it.
(hif-logior-expr, hif-logxor-expr, hif-logand-expr, hif-comp-expr)
(hif-logshift-expr, hif-muldiv-expr, hif-lognot, hif-shiftleft)
(hif-shiftright, hif-multiply, hif-divide, hif-modulo, hif-equal)
(hif-logxor, hif-comma): New functions.
2014-01-28 Glenn Morris <rgm@gnu.org> 2014-01-28 Glenn Morris <rgm@gnu.org>
* textmodes/fill.el (fill-single-char-nobreak-p): Doc tweak. * textmodes/fill.el (fill-single-char-nobreak-p): Doc tweak.
......
...@@ -35,9 +35,7 @@ ...@@ -35,9 +35,7 @@
;; M-x hide-ifdefs or C-c @ h ;; M-x hide-ifdefs or C-c @ h
;; ;;
;; Hide-ifdef suppresses the display of code that the preprocessor wouldn't ;; Hide-ifdef suppresses the display of code that the preprocessor wouldn't
;; pass through. The support of constant expressions in #if lines is ;; pass through. Support complete C/C++ expression and precedence.
;; limited to identifiers, parens, and the operators: &&, ||, !, and
;; "defined". Please extend this.
;; ;;
;; The hidden code is marked by ellipses (...). Be ;; The hidden code is marked by ellipses (...). Be
;; cautious when editing near ellipses, since the hidden text is ;; cautious when editing near ellipses, since the hidden text is
...@@ -97,6 +95,9 @@ ...@@ -97,6 +95,9 @@
;; ;;
;; Written by Brian Marick, at Gould, Computer Systems Division, Urbana IL. ;; Written by Brian Marick, at Gould, Computer Systems Division, Urbana IL.
;; Extensively modified by Daniel LaLiberte (while at Gould). ;; Extensively modified by Daniel LaLiberte (while at Gould).
;;
;; Extensively modified by Luke Lee in 2013 to support complete C expression
;; evaluation.
;;; Code: ;;; Code:
...@@ -368,26 +369,44 @@ that form should be displayed.") ...@@ -368,26 +369,44 @@ that form should be displayed.")
(defvar hif-token-list) (defvar hif-token-list)
(defconst hif-token-alist (defconst hif-token-alist
'(("||" . or) '(("||" . hif-or)
("&&" . and) ("&&" . hif-and)
("|" . hif-logior) ("|" . hif-logior)
("^" . hif-logxor)
("&" . hif-logand) ("&" . hif-logand)
("==" . equal) ("<<" . hif-shiftleft)
(">>" . hif-shiftright)
("==" . hif-equal)
;; Note: we include tokens like `=' which aren't supported by CPP's
;; expression syntax, because they are still relevant for the tokenizer,
;; especially in conjunction with ##.
("=" . hif-assign)
("!=" . hif-notequal) ("!=" . hif-notequal)
("!" . not) ("##" . hif-token-concat)
("(" . lparen) ("!" . hif-not)
(")" . rparen) ("~" . hif-lognot)
("(" . hif-lparen)
(")" . hif-rparen)
(">" . hif-greater) (">" . hif-greater)
("<" . hif-less) ("<" . hif-less)
(">=" . hif-greater-equal) (">=" . hif-greater-equal)
("<=" . hif-less-equal) ("<=" . hif-less-equal)
("+" . hif-plus) ("+" . hif-plus)
("-" . hif-minus) ("-" . hif-minus)
("*" . hif-multiply)
("/" . hif-divide)
("%" . hif-modulo)
("?" . hif-conditional) ("?" . hif-conditional)
(":" . hif-colon))) (":" . hif-colon)))
(defconst hif-token-regexp (defconst hif-token-regexp
(concat (regexp-opt (mapcar 'car hif-token-alist)) "\\|\\w+")) (concat (regexp-opt (mapcar 'car hif-token-alist))
"\\|0x[0-9a-fA-F]+\\.?[0-9a-fA-F]*"
"\\|[0-9]+\\.?[0-9]*" ;; decimal/octal
"\\|\\w+"))
(defconst hif-string-literal-regexp "\\(\"\\(?:[^\"\\]\\|\\\\.\\)*\"\\)")
(defun hif-tokenize (start end) (defun hif-tokenize (start end)
"Separate string between START and END into a list of tokens." "Separate string between START and END into a list of tokens."
...@@ -401,23 +420,63 @@ that form should be displayed.") ...@@ -401,23 +420,63 @@ that form should be displayed.")
((looking-at "\\\\\n") ((looking-at "\\\\\n")
(forward-char 2)) (forward-char 2))
((looking-at hif-string-literal-regexp)
(push (substring-no-properties (match-string 1)) token-list)
(goto-char (match-end 0)))
((looking-at hif-token-regexp) ((looking-at hif-token-regexp)
(let ((token (buffer-substring (point) (match-end 0)))) (let ((token (buffer-substring (point) (match-end 0))))
(goto-char (match-end 0)) (goto-char (match-end 0))
;; (message "token: %s" token) (sit-for 1) ;; (message "token: %s" token) (sit-for 1)
(push (or (cdr (assoc token hif-token-alist)) (push
(if (string-equal token "defined") 'hif-defined) (or (cdr (assoc token hif-token-alist))
(if (string-match "\\`[0-9]*\\'" token) (if (string-equal token "defined") 'hif-defined)
(string-to-number token)) ;; TODO:
(intern token)) ;; 1. postfix 'l', 'll', 'ul' and 'ull'
token-list))) ;; 2. floating number formats
;; 3. hexadecimal/octal floats
;; 4. 098 is interpreted as octal conversion error
;; FIXME: string-to-number does not convert hex floats
(if (string-match "0x\\([0-9a-fA-F]+\\.?[0-9a-fA-F]*\\)"
token)
(string-to-number (match-string 1 token) 16)) ;; hex
;; FIXME: string-to-number does not convert octal floats
(if (string-match "\\`0[0-9]+\\(\\.[0-9]+\\)?\\'" token)
(string-to-number token 8)) ;; octal
(if (string-match "\\`[1-9][0-9]*\\(\\.[0-9]+\\)?\\'"
token)
(string-to-number token)) ;; decimal
(intern token))
token-list)))
(t (error "Bad #if expression: %s" (buffer-string))))))) (t (error "Bad #if expression: %s" (buffer-string)))))))
(nreverse token-list))) (nreverse token-list)))
;;;----------------------------------------------------------------- ;;------------------------------------------------------------------------
;;; Translate C preprocessor #if expressions using recursive descent. ;; Translate C preprocessor #if expressions using recursive descent.
;;; This parser is limited to the operators &&, ||, !, and "defined". ;; This parser was limited to the operators &&, ||, !, and "defined".
;;; Added ==, !=, +, and -. Gary Oberbrunner, garyo@avs.com, 8/9/94 ;; Added ==, !=, +, and -. Gary Oberbrunner, garyo@avs.com, 8/9/94
;;
;; Implement the C language operator precedence table. Add all those
;; missing operators that could be used in macros. Luke Lee 2013-09-04
;; | Operator Type | Operator | Associativity |
;; +----------------------+-----------------------------+---------------+
;; | Primary Expression | () [] . -> expr++ expr-- | left-to-right |
;; | Unary Operators | * & + - ! ~ ++expr --expr | right-to-left |
;; | | (typecast) sizeof | |
;; | Binary Operators | * / % | left-to-right |
;; | | + - | |
;; | | >> << | |
;; | | < > <= >= | |
;; | | == != | |
;; | | & | |
;; | | ^ | |
;; | | | | |
;; | | && | |
;; | | || | |
;; | Ternary Operator | ?: | right-to-left |
;; x| Assignment Operators | = += -= *= /= %= >>= <<= &= | right-to-left |
;; | | ^= = | |
;; | Comma | , | left-to-right |
(defsubst hif-nexttoken () (defsubst hif-nexttoken ()
"Pop the next token from token-list into the let variable \"hif-token\"." "Pop the next token from token-list into the let variable \"hif-token\"."
...@@ -428,10 +487,24 @@ that form should be displayed.") ...@@ -428,10 +487,24 @@ that form should be displayed.")
(let ((hif-token-list token-list)) (let ((hif-token-list token-list))
(hif-nexttoken) (hif-nexttoken)
(prog1 (prog1
(hif-expr) (and hif-token
(hif-exprlist))
(if hif-token ; is there still a token? (if hif-token ; is there still a token?
(error "Error: unexpected token: %s" hif-token))))) (error "Error: unexpected token: %s" hif-token)))))
(defun hif-exprlist ()
"Parse an exprlist: expr { ',' expr}"
(let ((result (hif-expr)))
(if (eq hif-token 'hif-comma)
(let ((temp (list result)))
(while
(progn
(hif-nexttoken)
(push (hif-expr) temp)
(eq hif-token 'hif-comma)))
(cons 'hif-comma (nreverse temp)))
result)))
(defun hif-expr () (defun hif-expr ()
"Parse an expression as found in #if. "Parse an expression as found in #if.
expr : or-expr | or-expr '?' expr ':' expr." expr : or-expr | or-expr '?' expr ':' expr."
...@@ -448,67 +521,125 @@ that form should be displayed.") ...@@ -448,67 +521,125 @@ that form should be displayed.")
result)) result))
(defun hif-or-expr () (defun hif-or-expr ()
"Parse n or-expr : and-expr | or-expr '||' and-expr." "Parse an or-expr : and-expr | or-expr '||' and-expr."
(let ((result (hif-and-expr))) (let ((result (hif-and-expr)))
(while (eq hif-token 'or) (while (eq hif-token 'hif-or)
(hif-nexttoken) (hif-nexttoken)
(setq result (list 'hif-or result (hif-and-expr)))) (setq result (list 'hif-or result (hif-and-expr))))
result)) result))
(defun hif-and-expr () (defun hif-and-expr ()
"Parse an and-expr : eq-expr | and-expr '&&' eq-expr." "Parse an and-expr : logior-expr | and-expr '&&' logior-expr."
(let ((result (hif-logior-expr)))
(while (eq hif-token 'hif-and)
(hif-nexttoken)
(setq result (list 'hif-and result (hif-logior-expr))))
result))
(defun hif-logior-expr ()
"Parse a logor-expr : logxor-expr | logor-expr '|' logxor-expr."
(let ((result (hif-logxor-expr)))
(while (eq hif-token 'hif-logior)
(hif-nexttoken)
(setq result (list 'hif-logior result (hif-logxor-expr))))
result))
(defun hif-logxor-expr ()
"Parse a logxor-expr : logand-expr | logxor-expr '^' logand-expr."
(let ((result (hif-logand-expr)))
(while (eq hif-token 'hif-logxor)
(hif-nexttoken)
(setq result (list 'hif-logxor result (hif-logand-expr))))
result))
(defun hif-logand-expr ()
"Parse a logand-expr : eq-expr | logand-expr '&' eq-expr."
(let ((result (hif-eq-expr))) (let ((result (hif-eq-expr)))
(while (eq hif-token 'and) (while (eq hif-token 'hif-logand)
(hif-nexttoken) (hif-nexttoken)
(setq result (list 'hif-and result (hif-eq-expr)))) (setq result (list 'hif-logand result (hif-eq-expr))))
result)) result))
(defun hif-eq-expr () (defun hif-eq-expr ()
"Parse an eq-expr : math | eq-expr `=='|`!='|`<'|`>'|`>='|`<=' math." "Parse an eq-expr : comp | eq-expr `=='|`!=' comp."
(let ((result (hif-math)) (let ((result (hif-comp-expr))
(eq-token nil)) (eq-token nil))
(while (memq hif-token '(equal hif-notequal hif-greater hif-less (while (memq hif-token '(hif-equal hif-notequal))
hif-greater-equal hif-less-equal))
(setq eq-token hif-token) (setq eq-token hif-token)
(hif-nexttoken) (hif-nexttoken)
(setq result (list eq-token result (hif-math)))) (setq result (list eq-token result (hif-comp-expr))))
result))
(defun hif-comp-expr ()
"Parse a comp-expr : logshift | comp-expr `<'|`>'|`>='|`<=' logshift."
(let ((result (hif-logshift-expr))
(comp-token nil))
(while (memq hif-token '(hif-greater hif-less hif-greater-equal hif-less-equal))
(setq comp-token hif-token)
(hif-nexttoken)
(setq result (list comp-token result (hif-logshift-expr))))
result))
(defun hif-logshift-expr ()
"Parse a logshift : math | logshift `<<'|`>>' math."
(let ((result (hif-math))
(shift-token nil))
(while (memq hif-token '(hif-shiftleft hif-shiftright))
(setq shift-token hif-token)
(hif-nexttoken)
(setq result (list shift-token result (hif-math))))
result)) result))
(defun hif-math () (defun hif-math ()
"Parse an expression with + or - and simpler things. "Parse an expression with + or -.
math : factor | math '+|-' factor." math : muldiv | math '+|-' muldiv."
(let ((result (hif-muldiv-expr))
(math-op nil))
(while (memq hif-token '(hif-plus hif-minus))
(setq math-op hif-token)
(hif-nexttoken)
(setq result (list math-op result (hif-muldiv-expr))))
result))
(defun hif-muldiv-expr ()
"Parse an expression with *,/,%.
muldiv : factor | muldiv '*|/|%' factor."
(let ((result (hif-factor)) (let ((result (hif-factor))
(math-op nil)) (math-op nil))
(while (memq hif-token '(hif-plus hif-minus hif-logior hif-logand)) (while (memq hif-token '(hif-multiply hif-divide hif-modulo))
(setq math-op hif-token) (setq math-op hif-token)
(hif-nexttoken) (hif-nexttoken)
(setq result (list math-op result (hif-factor)))) (setq result (list math-op result (hif-factor))))
result)) result))
(defun hif-factor () (defun hif-factor ()
"Parse a factor: '!' factor | '(' expr ')' | 'defined(' id ')' | id." "Parse a factor: '!' factor | '~' factor | '(' expr ')' | 'defined(' id ')' | 'id(parmlist)' | strings | id."
(cond (cond
((eq hif-token 'not) ((eq hif-token 'hif-not)
(hif-nexttoken) (hif-nexttoken)
(list 'hif-not (hif-factor))) (list 'hif-not (hif-factor)))
((eq hif-token 'lparen) ((eq hif-token 'hif-lognot)
(hif-nexttoken) (hif-nexttoken)
(let ((result (hif-expr))) (list 'hif-lognot (hif-factor)))
(if (not (eq hif-token 'rparen))
((eq hif-token 'hif-lparen)
(hif-nexttoken)
(let ((result (hif-exprlist)))
(if (not (eq hif-token 'hif-rparen))
(error "Bad token in parenthesized expression: %s" hif-token) (error "Bad token in parenthesized expression: %s" hif-token)
(hif-nexttoken) (hif-nexttoken)
result))) result)))
((eq hif-token 'hif-defined) ((eq hif-token 'hif-defined)
(hif-nexttoken) (hif-nexttoken)
(let ((paren (when (eq hif-token 'lparen) (hif-nexttoken) t)) (let ((paren (when (eq hif-token 'hif-lparen) (hif-nexttoken) t))
(ident hif-token)) (ident hif-token))
(if (memq hif-token '(or and not hif-defined lparen rparen)) (if (memq hif-token '(or and not hif-defined hif-lparen hif-rparen))
(error "Error: unexpected token: %s" hif-token)) (error "Error: unexpected token: %s" hif-token))
(when paren (when paren
(hif-nexttoken) (hif-nexttoken)
(unless (eq hif-token 'rparen) (unless (eq hif-token 'hif-rparen)
(error "Error: expected \")\" after identifier"))) (error "Error: expected \")\" after identifier")))
(hif-nexttoken) (hif-nexttoken)
`(hif-defined (quote ,ident)))) `(hif-defined (quote ,ident))))
...@@ -541,22 +672,54 @@ that form should be displayed.") ...@@ -541,22 +672,54 @@ that form should be displayed.")
(or (not (zerop (hif-mathify a))) (not (zerop (hif-mathify b))))) (or (not (zerop (hif-mathify a))) (not (zerop (hif-mathify b)))))
(defun hif-not (a) (defun hif-not (a)
(zerop (hif-mathify a))) (zerop (hif-mathify a)))
(defun hif-lognot (a)
(lognot (hif-mathify a)))
(defmacro hif-mathify-binop (fun) (defmacro hif-mathify-binop (fun)
`(lambda (a b) `(lambda (a b)
,(format "Like `%s' but treat t and nil as 1 and 0." fun) ,(format "Like `%s' but treat t and nil as 1 and 0." fun)
(,fun (hif-mathify a) (hif-mathify b)))) (,fun (hif-mathify a) (hif-mathify b))))
(defun hif-shiftleft (a b)
(setq a (hif-mathify a))
(setq b (hif-mathify b))
(if (< a 0)
(ash a b)
(lsh a b)))
(defun hif-shiftright (a b)
(setq a (hif-mathify a))
(setq b (hif-mathify b))
(if (< a 0)
(ash a (- b))
(lsh a (- b))))
(defalias 'hif-multiply (hif-mathify-binop *))
(defalias 'hif-divide (hif-mathify-binop /))
(defalias 'hif-modulo (hif-mathify-binop %))
(defalias 'hif-plus (hif-mathify-binop +)) (defalias 'hif-plus (hif-mathify-binop +))
(defalias 'hif-minus (hif-mathify-binop -)) (defalias 'hif-minus (hif-mathify-binop -))
(defalias 'hif-equal (hif-mathify-binop =))
(defalias 'hif-notequal (hif-mathify-binop /=)) (defalias 'hif-notequal (hif-mathify-binop /=))
(defalias 'hif-greater (hif-mathify-binop >)) (defalias 'hif-greater (hif-mathify-binop >))
(defalias 'hif-less (hif-mathify-binop <)) (defalias 'hif-less (hif-mathify-binop <))
(defalias 'hif-greater-equal (hif-mathify-binop >=)) (defalias 'hif-greater-equal (hif-mathify-binop >=))
(defalias 'hif-less-equal (hif-mathify-binop <=)) (defalias 'hif-less-equal (hif-mathify-binop <=))
(defalias 'hif-logior (hif-mathify-binop logior)) (defalias 'hif-logior (hif-mathify-binop logior))
(defalias 'hif-logxor (hif-mathify-binop logxor))
(defalias 'hif-logand (hif-mathify-binop logand)) (defalias 'hif-logand (hif-mathify-binop logand))
(defun hif-comma (&rest expr)
"Evaluate a list of expr, return the result of the last item"
(let ((result nil))
(dolist (e expr)
(ignore-errors
(setq result (funcall hide-ifdef-evaluator e))))
result))
;;;----------- end of parser ----------------------- ;;;----------- end of parser -----------------------
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment