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." )) |