Updated version: Use emacs & Graphviz to plot data structure

简介: Updated version to translate a C struct into corresponding dot file.
转载请注明出处

 

Refer to

http://emacser.com/emacs_graphviz_ds.htm or

http://blog.163.com/vic_kk/blog/static/494705242011526292895/

for orignal infomation.

 

;; Function used to add fields of struct into a dot file (for Graphviz).
 
;;;;; Dot templates
 
(defconst yyc/dot-head "subgraph cluster_%s {
    node [shape=record fontsize=12 fontname=Courier style=filled];
    color = lightgray;
    style=filled;
    label = \"Struct %s\";
    edge[color=\"brown\"];"
  "Header part of dot file.")
(defconst yyc/dot-tail "
}"
  "Tail part of dot")
(defconst yyc/dot-node-head
  "
    node_%s[shape=record
            label=\"<f0>*** STRUCT %s ***|\\"
  "Format of node.")
(defconst yyc/dot-node-tail "
\"];"
  "Format of node.")
 
(defconst attr_str "
<f%d>+%s : %s\\l|\\" "nil")
 
(defconst attr_func "
<f%d>-%s() : %s\\l|\\" "nil")
 
;;;;; Regular expressions to match a field of a struct.
 
(defconst r_attr_str "[ \t]+\\(.*+\\)[ \t]+\\(.*?\\);\\([ \t]*/[/\\*].]*\\)?$"
  "Regular expression for matching struct fields.")
 
(defconst r_name "\\_<\\(typedef[ \t]+\\)?struct[ \t]+\\(.*\\)?[ \t]*"
  "Regular expression for mating struct name")
 
(defconst r_func_l "\(.*"
  "Regular expression to match a function")
(defconst r_func_r ".*\)"
  "Regular expression to match a function")
 
(defconst r_comments "^[ \t/\\*][/\\*]+"
  "Regular expression to match a commentted field.")
 
 
(defconst r_struct_func
  "^[ \t]*\\(.+?\\)[ \t]*\(\\*\\(.*?\\)\)[ \t]*(\\(?:.\\|
\\)*?);"
  "Regular expression to match a function decleration in a struct.")
 
(defconst r_match_semicol
  (rx (+? anything) ";"))
 
(defconst r_match_attr
  (rx (+? (not (any "(" ")" "{" "}"))) ";"))
 
(defconst r_match_func
  (rx (+? (or alnum "_" blank)) "(*" (+? (or alnum "_")) ")"
      (zero-or-more blank) "(" (*? anything) ");"))
 
(defconst r_match_tag
  (rx (zero-or-more blank) (zero-or-one "typedef" (one-or-more  blank))
      "struct" (zero-or-more (or alnum "_" blank))
      (zero-or-one "
") (zero-or-more blank) "{"))
 
(defun get_struct_tag (decleration)
  "Abstract decleration from a string"
  (if (string-match r_name decleration 0)
      (car (split-string (match-string 2 decleration) "{"))
    nil))
 
(defun skip(msg x)
  (if x
      (message (format "Skip invalid syntax for function: %s." msg))
  (message (format "Skip invalid syntax for struct field: %s." msg))
  )
)
 
(defun yyc/datastruct-to-dot (start end)
  "Translate a C struct into dot file which can be turned into images using graphviz."
  (interactive "rp")
  (let* ((tmp_str "")
         (var-name "")
         (var-type "")
         (counter 0)
         (next-begin 0)
         (pos-cur 0)
         (struct-name "")
         (header-str "")
         (pos-end 0)
         (var-defination (buffer-substring-no-properties start end))
         (item_str "")
         )
    (defun iter (pos)
      (if (string-match r_match_tag var-defination pos) ;; Declerad a struct
          (progn
            (setq pos-end (match-end 0))
            (setq item_str (substring var-defination pos pos-end))
            (setq struct-name (get_struct_tag item_str))
            (setq header-str
                  (format yyc/dot-head struct-name struct-name))
            (setq tmp_str
                  (format yyc/dot-node-head struct-name struct-name))
            (setq pos-cur (1+ pos-end))
            (iter pos-cur))
        (progn
          (if (string-match r_match_semicol var-defination pos)
              (progn
                (setq pos-end (match-end 0))
                (setq item_str (substring var-defination pos pos-end))
                (if (string-match r_match_func item_str 0) ;; Function
                    (progn
                      (if (string-match r_struct_func item_str 0)
                          (progn
                            (setq var-type
                                  (match-string 1 item_str))
                            (setq var-name
                                  (match-string 2 item_str))
                            (setq next-begin (match-end 0))
                            (if (string-match r_comments var-type 0) ;Comments
                                nil
                              (progn
                                (setq counter (+ counter 1))
                                (setq tmp_str
                                      (concat tmp_str
                                              (format attr_func
                                                      counter var-name var-type))))))
                        (skip item_str t)
                        )
                      )
                  (progn
                    (if (equal (string-match r_match_attr item_str 0) 0)
                        (progn
                          (if (string-match r_attr_str item_str 0)
                              (progn
                                (setq var-type
                                      (match-string 1 item_str))
                                (setq var-name
                                      (match-string 2 item_str))
                                (if (string-match r_comments var-type 0)
                                    nil
                                  (progn
                                    (setq counter (+ counter 1))
                                    (setq tmp_str
                                          (concat tmp_str
                                                  (format attr_str
                                                          counter var-name
                                                          var-type))))))
                            (skip item_str nil)))
                      (skip item_str nil))))
                (iter pos-end))))))
    (save-excursion
      (iter 0)
      (set-buffer (get-buffer-create "tmp.dot"))
      (graphviz-dot-mode)
      (goto-char (point-max))
      (insert  header-str tmp_str )
      (goto-char (point-max))
      (delete-char -1)
      (insert "<f999>\\"yyc/dot-node-tail yyc/dot-tail)
      )
    (if (one-window-p)
        (split-window-vertically))
    (switch-to-buffer-other-window "tmp.dot")
    (goto-char (point-min))
    )
  (message "Finished, please refer to *tmp.dot* buffer."))


posted @ 2011-08-19 13:12  英超  Views(236)  Comments(0Edit  收藏  举报