From 17790c7dadd20c3c3bdfa5d4d0f809108cf9d494 Mon Sep 17 00:00:00 2001 From: Eric Schulte Date: Fri, 26 Mar 2010 13:16:56 -0600 Subject: [PATCH 1/6] babel: limited initial support for C and similar languages --- contrib/babel/lisp/langs/org-babel-C.el | 117 ++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 contrib/babel/lisp/langs/org-babel-C.el diff --git a/contrib/babel/lisp/langs/org-babel-C.el b/contrib/babel/lisp/langs/org-babel-C.el new file mode 100644 index 000000000..836eba3bb --- /dev/null +++ b/contrib/babel/lisp/langs/org-babel-C.el @@ -0,0 +1,117 @@ +;;; org-babel-C.el --- org-babel functions for C and similar languages + +;; Copyright (C) 2010 Eric Schulte + +;; Author: Eric Schulte +;; Keywords: literate programming, reproducible research +;; Homepage: http://orgmode.org +;; Version: 0.01 + +;;; License: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;; Org-Babel support for evaluating C code. +;; +;; very limited implementation: +;; - currently only support :results output +;; - not much in the way of error feedback + +;;; Code: +(require 'org-babel) +(require 'cc-mode) + +(org-babel-add-interpreter "C") +(add-to-list 'org-babel-tangle-langs '("C" "c" nil)) + +(org-babel-add-interpreter "cpp") +(add-to-list 'org-babel-tangle-langs '("cpp" "cpp" nil)) + +(org-babel-add-interpreter "c++") +(add-to-list 'org-babel-tangle-langs '("c++" "cpp" nil)) + +(defvar org-babel-C-compiler "gcc" + "Command used to compile a C source code file into an + executable.") + +(defun org-babel-execute:cpp (body params) + (org-babel-execute:C body params)) + +(defun org-babel-execute:c++ (body params) + (org-babel-execute:C body params)) + +(defun org-babel-execute:C (body params) + "Execute a block of C commands with org-babel. This +function is called by `org-babel-execute-src-block'." + (message "executing C source code block") + (let* ((processed-params (org-babel-process-params params)) + (tmp-src-file (make-temp-file "org-babel-C-src" nil ".c")) + (tmp-bin-file (make-temp-file "org-babel-C-bin")) + (tmp-out-file (make-temp-file "org-babel-C-out")) + (flags (cdr (assoc :flags params))) + (vars (second processed-params)) + (includes (cdr (assoc :includes params))) + (defines (cdr (assoc :defines params))) + (full-body (concat + ;; includes + (mapconcat + (lambda (inc) (format "#include %s" inc)) + (if (listp includes) includes (list includes)) "\n") + ;; defines + (mapconcat + (lambda (inc) (format "#define %s" inc)) + (if (listp defines) defines (list defines)) "\n") + ;; variables + (mapconcat 'org-babel-C-var-to-C vars "\n") + ;; body + "\n" body "\n\n")) + (bin (progn + (with-temp-file tmp-src-file (insert full-body)) + (shell-command + (format "%s -o %s %s %s" + org-babel-C-compiler tmp-bin-file + (mapconcat 'identity (if (listp flags) flags (list flags)) " ") + tmp-src-file)) + tmp-bin-file))) + (org-babel-read (org-babel-trim (shell-command-to-string bin))))) + +(defun org-babel-prep-session:C (session params) + "C is a compiled languages -- no support for sessions" + (error "C is a compiled languages -- no support for sessions")) + +(defun org-babel-load-session:C (session body params) + "C is a compiled languages -- no support for sessions" + (error "C is a compiled languages -- no support for sessions")) + +;; helper functions + +(defun org-babel-C-var-to-C (pair) + "Convert an elisp val into a string of C code specifying a var +of the same value. TODO list support." + (let* ((var (car pair)) + (val (cdr pair)) + (type (cond + ((integerp val) "int") + ((floatp val) "double") + ((characterp val) "char") + ((stringp val) (format "char[%d]" (length val))) + (t "u32")))) + (format "%s %S = %S;" type var val))) + +(provide 'org-babel-C) +;;; org-babel-C.el ends here From e3fbc98b26a277eb6420f62eb0a842d76ab29813 Mon Sep 17 00:00:00 2001 From: Eric Schulte Date: Fri, 26 Mar 2010 16:03:54 -0600 Subject: [PATCH 2/6] babel: removed errant reference to R from org-babel.el --- contrib/babel/lisp/org-babel.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/babel/lisp/org-babel.el b/contrib/babel/lisp/org-babel.el index 767fb588b..c368c210b 100644 --- a/contrib/babel/lisp/org-babel.el +++ b/contrib/babel/lisp/org-babel.el @@ -1090,7 +1090,7 @@ the table is trivial, then return it as a scalar." result)))) (defun org-babel-string-read (cell) - "Strip nested \"s from around strings in exported R values." + "Strip nested \"s from around strings." (org-babel-read (or (and (stringp cell) (string-match "\\\"\\(.+\\)\\\"" cell) (match-string 1 cell)) From b61019489c9252c42cb6bd7f9c8dab4957f8364a Mon Sep 17 00:00:00 2001 From: Eric Schulte Date: Fri, 26 Mar 2010 17:12:43 -0600 Subject: [PATCH 3/6] babel: org-babel-C now displays compilation error messages --- contrib/babel/lisp/langs/org-babel-C.el | 39 ++++++++++++++++++------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/contrib/babel/lisp/langs/org-babel-C.el b/contrib/babel/lisp/langs/org-babel-C.el index 836eba3bb..9bb339971 100644 --- a/contrib/babel/lisp/langs/org-babel-C.el +++ b/contrib/babel/lisp/langs/org-babel-C.el @@ -79,16 +79,35 @@ function is called by `org-babel-execute-src-block'." ;; variables (mapconcat 'org-babel-C-var-to-C vars "\n") ;; body - "\n" body "\n\n")) - (bin (progn - (with-temp-file tmp-src-file (insert full-body)) - (shell-command - (format "%s -o %s %s %s" - org-babel-C-compiler tmp-bin-file - (mapconcat 'identity (if (listp flags) flags (list flags)) " ") - tmp-src-file)) - tmp-bin-file))) - (org-babel-read (org-babel-trim (shell-command-to-string bin))))) + "\n" (org-babel-C-ensure-main-wrap body) "\n\n")) + (error-buf (get-buffer-create "*Org-Babel Error Output*")) + (compile + (progn + (with-temp-file tmp-src-file (insert full-body)) + (with-temp-buffer + (org-babel-shell-command-on-region + (point-min) (point-max) + (format "%s -o %s %s %s" + org-babel-C-compiler + tmp-bin-file + (mapconcat 'identity + (if (listp flags) flags (list flags)) " ") + tmp-src-file) + (current-buffer) 'replace error-buf))))) + (if (= compile 0) + (org-babel-read + (org-babel-trim + (with-temp-buffer + (org-babel-shell-command-on-region + (point-min) (point-max) tmp-bin-file (current-buffer) 'replace) + (buffer-string)))) + (progn (display-buffer error-buf) nil)))) + +(defun org-babel-C-ensure-main-wrap (body) + "Wrap body in a \"main\" function call if none exists." + (if (string-match "^[ \t]*[intvoid][ \t]*main[ \t]*(.*)" body) + body + (format "int main() {\n%s\n}\n" body))) (defun org-babel-prep-session:C (session params) "C is a compiled languages -- no support for sessions" From 22e4cd9b6d0cd37f8bc4ec880c39c20689125ad4 Mon Sep 17 00:00:00 2001 From: Eric Schulte Date: Fri, 26 Mar 2010 18:52:16 -0600 Subject: [PATCH 4/6] babel: org-babel-c more robust, better error messages and c++ support --- contrib/babel/lisp/langs/org-babel-C.el | 72 ++++++++++++++++--------- 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/contrib/babel/lisp/langs/org-babel-C.el b/contrib/babel/lisp/langs/org-babel-C.el index 9bb339971..9ed04a26a 100644 --- a/contrib/babel/lisp/langs/org-babel-C.el +++ b/contrib/babel/lisp/langs/org-babel-C.el @@ -39,9 +39,6 @@ (org-babel-add-interpreter "C") (add-to-list 'org-babel-tangle-langs '("C" "c" nil)) -(org-babel-add-interpreter "cpp") -(add-to-list 'org-babel-tangle-langs '("cpp" "cpp" nil)) - (org-babel-add-interpreter "c++") (add-to-list 'org-babel-tangle-langs '("c++" "cpp" nil)) @@ -49,37 +46,56 @@ "Command used to compile a C source code file into an executable.") +(defvar org-babel-c++-compiler "g++" + "Command used to compile a c++ source code file into an + executable.") + (defun org-babel-execute:cpp (body params) (org-babel-execute:C body params)) (defun org-babel-execute:c++ (body params) - (org-babel-execute:C body params)) + "Execute a block of C++ code with org-babel. This function is +called by `org-babel-execute-src-block'." + (let ((c-variant 'cpp)) (org-babel-C-execute body params))) (defun org-babel-execute:C (body params) - "Execute a block of C commands with org-babel. This -function is called by `org-babel-execute-src-block'." + "Execute a block of C code with org-babel. This function is +called by `org-babel-execute-src-block'." + (let ((c-variant 'c)) (org-babel-C-execute body params))) + +(defun org-babel-C-execute (body params) + "This should only be called by `org-babel-execute:C' or +`org-babel-execute:c++'." (message "executing C source code block") (let* ((processed-params (org-babel-process-params params)) - (tmp-src-file (make-temp-file "org-babel-C-src" nil ".c")) + (tmp-src-file (make-temp-file "org-babel-C-src" nil + (case c-variant + ('c ".c") + ('cpp ".cpp")))) (tmp-bin-file (make-temp-file "org-babel-C-bin")) (tmp-out-file (make-temp-file "org-babel-C-out")) (flags (cdr (assoc :flags params))) (vars (second processed-params)) - (includes (cdr (assoc :includes params))) - (defines (cdr (assoc :defines params))) - (full-body (concat - ;; includes - (mapconcat - (lambda (inc) (format "#include %s" inc)) - (if (listp includes) includes (list includes)) "\n") - ;; defines - (mapconcat - (lambda (inc) (format "#define %s" inc)) - (if (listp defines) defines (list defines)) "\n") - ;; variables - (mapconcat 'org-babel-C-var-to-C vars "\n") - ;; body - "\n" (org-babel-C-ensure-main-wrap body) "\n\n")) + (includes (org-babel-read + (or (cdr (assoc :includes params)) + (org-entry-get nil "includes" t)))) + (defines (org-babel-read + (or (cdr (assoc :includes params)) + (org-entry-get nil "defines" t)))) + (full-body (mapconcat 'identity + (list + ;; includes + (mapconcat + (lambda (inc) (format "#include %s" inc)) + (if (listp includes) includes (list includes)) "\n") + ;; defines + (mapconcat + (lambda (inc) (format "#define %s" inc)) + (if (listp defines) defines (list defines)) "\n") + ;; variables + (mapconcat 'org-babel-C-var-to-C vars "\n") + ;; body + "\n" (org-babel-C-ensure-main-wrap body) "\n") "\n")) (error-buf (get-buffer-create "*Org-Babel Error Output*")) (compile (progn @@ -88,7 +104,9 @@ function is called by `org-babel-execute-src-block'." (org-babel-shell-command-on-region (point-min) (point-max) (format "%s -o %s %s %s" - org-babel-C-compiler + (case c-variant + ('c org-babel-C-compiler) + ('cpp org-babel-c++-compiler)) tmp-bin-file (mapconcat 'identity (if (listp flags) flags (list flags)) " ") @@ -101,11 +119,15 @@ function is called by `org-babel-execute-src-block'." (org-babel-shell-command-on-region (point-min) (point-max) tmp-bin-file (current-buffer) 'replace) (buffer-string)))) - (progn (display-buffer error-buf) nil)))) + (progn + (with-current-buffer error-buf + (goto-char (point-max)) + (insert (concat "\n\n--body--\n" full-body))) + (display-buffer error-buf) nil)))) (defun org-babel-C-ensure-main-wrap (body) "Wrap body in a \"main\" function call if none exists." - (if (string-match "^[ \t]*[intvoid][ \t]*main[ \t]*(.*)" body) + (if (string-match "^[ \t]*[intvod]+[ \t]*main[ \t]*(.*)" body) body (format "int main() {\n%s\n}\n" body))) From fc28dd538b0d3c9ceeb99c28b5005f77b7ba7655 Mon Sep 17 00:00:00 2001 From: Eric Schulte Date: Fri, 26 Mar 2010 20:54:16 -0600 Subject: [PATCH 5/6] babel: shorter language names no longer shadow larger names Previously "R" could overshadow "Ruby", and "C" could overshadow "Clojure", causing blocks of the longer language name to fail to load. This issue has now been fixed --- contrib/babel/lisp/org-babel.el | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contrib/babel/lisp/org-babel.el b/contrib/babel/lisp/org-babel.el index c368c210b..43a6d0864 100644 --- a/contrib/babel/lisp/org-babel.el +++ b/contrib/babel/lisp/org-babel.el @@ -153,7 +153,10 @@ can not be resolved.") "Add INTERPRETER to `org-babel-interpreters' and update `org-babel-src-block-regexp' appropriately." (unless (member interpreter org-babel-interpreters) - (setq org-babel-interpreters (cons interpreter org-babel-interpreters)) + (setq org-babel-interpreters + (sort (cons interpreter org-babel-interpreters) + (lambda (left right) + (> (length left) (length right))))) (org-babel-set-interpreters 'org-babel-interpreters org-babel-interpreters))) (defcustom org-babel-interpreters '() From 8ecc86d49e3724f882dda593c6cf307581195131 Mon Sep 17 00:00:00 2001 From: Eric Schulte Date: Sat, 27 Mar 2010 08:20:38 -0600 Subject: [PATCH 6/6] babel: better variable initialization for org-babel-c --- contrib/babel/lisp/langs/org-babel-C.el | 31 +++++++++++++++++-------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/contrib/babel/lisp/langs/org-babel-C.el b/contrib/babel/lisp/langs/org-babel-C.el index 9ed04a26a..9a7627e3d 100644 --- a/contrib/babel/lisp/langs/org-babel-C.el +++ b/contrib/babel/lisp/langs/org-babel-C.el @@ -122,7 +122,8 @@ called by `org-babel-execute-src-block'." (progn (with-current-buffer error-buf (goto-char (point-max)) - (insert (concat "\n\n--body--\n" full-body))) + (insert (concat "\n\n--body--\n" full-body)) + (goto-char (point-min))) (display-buffer error-buf) nil)))) (defun org-babel-C-ensure-main-wrap (body) @@ -144,15 +145,25 @@ called by `org-babel-execute-src-block'." (defun org-babel-C-var-to-C (pair) "Convert an elisp val into a string of C code specifying a var of the same value. TODO list support." - (let* ((var (car pair)) - (val (cdr pair)) - (type (cond - ((integerp val) "int") - ((floatp val) "double") - ((characterp val) "char") - ((stringp val) (format "char[%d]" (length val))) - (t "u32")))) - (format "%s %S = %S;" type var val))) + (let ((var (car pair)) + (val (cdr pair))) + (when (symbolp val) + (setq val (symbol-name val)) + (when (= (length val) 1) + (setq val (string-to-char val)))) + (cond + ((integerp val) + (format "int %S = %S;" var val)) + ((floatp val) + (format "double %S = %S;" var val)) + ((or (characterp val)) + (format "char %S = '%S';" var val)) + ((stringp val) + (format "char %S[%d] = \"%s\";" + var (+ 1 (length val)) val)) + (t + (format "u32 %S = %S;" var val))))) + (provide 'org-babel-C) ;;; org-babel-C.el ends here