home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #30 / NN_1992_30.iso / spool / comp / sys / amiga / programm / 17449 < prev    next >
Encoding:
Text File  |  1992-12-16  |  20.3 KB  |  552 lines

  1. Path: sparky!uunet!mcsun!sunic!lunic!my!omega!pjotr
  2. From: pjotr@ludd.luth.se (Peter Sj|str|m)
  3. Newsgroups: comp.sys.amiga.programmer
  4. Subject: Re: Emacs and SAS/C
  5. Message-ID: <1992Dec17.000409.21932@ludd.luth.se>
  6. Date: 17 Dec 92 00:04:09 GMT
  7. References: <KOPNICKY.92Dec15025822@great-gray.owlnet.rice.edu>
  8. Organization: Lule} Tekniska H|gskolas Datorf|rening - Ludd
  9. Lines: 541
  10.  
  11. In <KOPNICKY.92Dec15025822@great-gray.owlnet.rice.edu> kopnicky@great-gray.owlnet.rice.edu (Lyle Warren Kopnicky) writes:
  12.  
  13. >I have just recently purchased SAS/C 6.0 and I know it allows you to
  14. >use whatever editor you wish.  This can be accomplished by changing a
  15. >tooltype or something.  But don't you also have to change the
  16. >appropriate ARexx scripts for use with the message browser?  I'm using
  17. >gnuemacs.  If anyone had the appropriate scripts, it would be very
  18. >helpful.  Thanks.
  19.  
  20.     I use elisp code to compile and jump to errors from within emacs.
  21. Here's my elisp code. It's compile.el and compile-ok.el. load compile-ok.el
  22. after you have loaded compile.el into emacs. Hope you don't need more of
  23. my elisp code. I am thinking of uploading a whole package soon, so
  24. hold on. You will have to guess a bit to adapt it to your own disks...
  25.  
  26.     I usually remap 'compile to C-x RETURN and 'next-error to C-x '.
  27.  
  28. compile.el:
  29. -----------
  30.  
  31. ;; Slightly altered by Linus 1990 to make it possible to change 
  32. ;; buffer names of grep and compile buffers and still have the
  33. ;; next-error function run correctly on last compiled buffer
  34. ;; Works fine on SAS 6.0 but a bit strange on gcc output - Pjotr
  35.  
  36. (defvar linus-compile t)
  37.  
  38. ;; Run compiler as inferior of Emacs, and parse its error messages.
  39. ;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
  40.  
  41. ;; This file is part of GNU Emacs.
  42.  
  43. ;; GNU Emacs is distributed in the hope that it will be useful,
  44. ;; but WITHOUT ANY WARRANTY.  No author or distributor
  45. ;; accepts responsibility to anyone for the consequences of using it
  46. ;; or for whether it serves any particular purpose or works at all,
  47. ;; unless he says so in writing.  Refer to the GNU Emacs General Public
  48. ;; License for full details.
  49.  
  50. ;; Everyone is granted permission to copy, modify and redistribute
  51. ;; GNU Emacs, but only under the conditions described in the
  52. ;; GNU Emacs General Public License.   A copy of this license is
  53. ;; supposed to have been given to you along with GNU Emacs so you
  54. ;; can know your rights and responsibilities.  It should be in a
  55. ;; file named COPYING.  Among other things, the copyright notice
  56. ;; and this notice must be preserved on all copies.
  57.  
  58. (provide 'compile)
  59.  
  60. ;;(defvar compilation-process nil
  61. ;;  "Process created by compile command, or nil if none exists now.
  62. ;;Note that the process may have been \"deleted\" and still
  63. ;;be the value of this variable.")
  64.  
  65. (defvar compilation-error-list nil
  66.   "List of error message descriptors for visiting erring functions.
  67. Each error descriptor is a list of length two.
  68. Its car is a marker pointing to an error message.
  69. Its cadr is a marker pointing to the text of the line the message is about,
  70.   or nil if that is not interesting.
  71. The value may be t instead of a list;
  72. this means that the buffer of error messages should be reparsed
  73. the next time the list of errors is wanted.")
  74.  
  75. (defvar compilation-parsing-end nil
  76.   "Position of end of buffer when last error messages parsed.")
  77.  
  78. (defvar compilation-parsing-continue nil
  79.   "Positions in last buffer you were parsing from.
  80. car is linenumber,
  81. cadr is a marker to that line and
  82. caddr is filename.")
  83.  
  84. (defvar compilation-error-message nil
  85.   "Message to print when no more matches for compilation-error-regexp are found")
  86.  
  87. (defvar compilation-error-regexp
  88.   "\\([^ \n]+\\(: *\\|, line \\|(\\)[0-9]+\\)\\|\\([0-9]+ *of *[^ \n]+\\)"
  89.   "Regular expression for filename/linenumber in error in compilation log.")
  90.  
  91. (defvar compilation-dont-ask nil
  92.   "*Non-nil means \\[compile] requires an argument to let you change
  93. the command.")
  94.  
  95.  
  96. (defvar compilation-buffer-name
  97.   "*compilation*"
  98.   "*Name of the buffer created by \\[compile].")
  99.  
  100. (defvar grep-buffer-name
  101.   "*grep*"
  102.   "*Name of the buffer created by \\[grep].")
  103.  
  104. (defvar grep-command-default
  105.   "grep -n "
  106.   "*Default command used to do a grep.")
  107.  
  108. (defvar grep-command
  109.   grep-command-default
  110.   "Last shell command used to do a grep; default for next grep.")
  111.  
  112. ;(defvar compile-command "dmake" ... G|rs i loaddefs)
  113. (setq compile-command "dmake ")
  114.  
  115. (defvar last-compilation-buffer compilation-buffer-name)
  116.  
  117. (defun compile (command)
  118.   "Compile the program including the current buffer.  Default: run make.
  119. Runs COMMAND, a shell command, in a separate process asynchronously
  120. with output going to the buffer with the name from compilation-buffer-name.
  121. To change the command give a numeric argument.
  122. You can then use the command next-error, on \\[next-error] to find the
  123. next error message and move to the source code that caused it."
  124.   (interactive (list (cond
  125.               ((or current-prefix-arg
  126.                (not compilation-dont-ask))
  127.                (read-string "Compile command: " compile-command))
  128.               (t compile-command))))
  129.   (setq compile-command command)
  130.   (compile1 compile-command "No more errors" compilation-buffer-name))
  131.  
  132. (defun grep (command)
  133.   "Run grep, with user-specified args, and collect output in a buffer.
  134. While grep runs asynchronously, you can use the \\[next-error] command
  135. to find the text that grep hits refer to.
  136. Without argument, prompts with last command.
  137. With argument, prompts with default command."
  138.   (interactive (list (read-string "Grep command: "
  139.                   (cond
  140.                    (current-prefix-arg grep-command-default)
  141.                    (t grep-command)))))
  142.   (setq grep-command command)
  143.   (compile1 (concat command (cond
  144.                  ((string-match "grep" command) " /dev/null")
  145.                  (t "")))
  146.         "No more grep hits" grep-buffer-name "Grep"))
  147.  
  148. (defun compile1 (command error-message compilation-buffer-name
  149.              &optional name-of-mode)
  150.   (save-some-buffers)
  151.   (let ((compilation-process (get-buffer-process compilation-buffer-name)))
  152.     (if compilation-process
  153.     (if (or (not (eq (process-status compilation-process) 'run))
  154.         (yes-or-no-p "A compilation process is running; kill it? "))
  155.         (condition-case ()
  156.         (let ((comp-proc compilation-process))
  157.           (interrupt-process comp-proc)
  158.           (sit-for 1)
  159.           (delete-process comp-proc))
  160.           (error nil))
  161.       (error "Cannot have two compilation processes")))
  162.     (setq compilation-process nil)
  163.     (compilation-forget-errors)
  164.     (setq compilation-error-list t)
  165.     (setq compilation-error-message error-message)
  166.     (if (get-buffer compilation-buffer-name)
  167.     (setq last-compilation-buffer (get-buffer compilation-buffer-name))
  168.       (setq last-compilation-buffer
  169.         (get-buffer-create compilation-buffer-name)))
  170.     (setq compilation-process
  171.       (start-process "compilation" last-compilation-buffer
  172.              shell-file-name
  173.              "-c" (concat "exec " command)))
  174.     (with-output-to-temp-buffer compilation-buffer-name
  175.       (princ "cd ")
  176.       (princ default-directory)
  177.       (terpri)
  178.       (princ command)
  179.       (terpri))
  180.     (let ((regexp compilation-error-regexp))
  181.       (save-excursion
  182.     (switch-to-buffer last-compilation-buffer)
  183.     (make-local-variable 'compilation-error-regexp)
  184.     (setq compilation-error-regexp regexp)))
  185.     (set-process-sentinel compilation-process 'compilation-sentinel)
  186.     (let* ((thisdir default-directory)
  187.        (outbuf (process-buffer compilation-process))
  188.        (outwin (get-buffer-window outbuf)))
  189.       (if (eq outbuf (current-buffer))
  190.       (goto-char (point-max)))
  191.       (save-excursion
  192.     (set-buffer outbuf)
  193.     (buffer-flush-undo outbuf)
  194.     (let ((start (save-excursion (set-buffer outbuf) (point-min))))
  195.       (set-window-start outwin start)
  196.       (or (eq outwin (selected-window))
  197.           (set-window-point outwin start)))
  198.     (setq default-directory thisdir)
  199.     (fundamental-mode)
  200.     (setq mode-name (or name-of-mode "Compilation"))
  201.     ;; Make log buffer's mode line show process state
  202.     (setq mode-line-process '(": %s"))))))
  203.  
  204. ;; Called when compilation process changes state.
  205.  
  206. (defun compilation-sentinel (proc msg)
  207.   (cond ((null (buffer-name (process-buffer proc)))
  208.      ;; buffer killed
  209.      (set-process-buffer proc nil))
  210.     ((memq (process-status proc) '(signal exit))
  211.      (let* ((obuf (current-buffer))
  212.         (omax (point-max))
  213.         (opoint (point)))
  214.        ;; save-excursion isn't the right thing if
  215.        ;;  process-buffer is current-buffer
  216.        (unwind-protect
  217.            (progn
  218.          ;; Write something in *compilation* and hack its mode line,
  219.          (set-buffer (process-buffer proc))
  220.          (goto-char (point-max))
  221.          (insert ?\n mode-name " " msg)
  222.          (forward-char -1)
  223.          (insert " at "
  224.              (substring (current-time-string) 0 -5))
  225.          (forward-char 1)
  226.          (setq mode-line-process
  227.                (concat ": "
  228.                    (symbol-name (process-status proc))))
  229.          ;; If buffer and mode line will show that the process
  230.          ;; is dead, we can delete it now.  Otherwise it
  231.          ;; will stay around until M-x list-processes.
  232.          (delete-process proc))
  233. ;;         (setq compilation-process nil)
  234.          ;; Force mode line redisplay soon
  235.          (set-buffer-modified-p (buffer-modified-p)))
  236.        (if (< opoint omax)
  237.            (goto-char opoint))
  238.        (set-buffer obuf)))))
  239.  
  240. (defun kill-compilation ()
  241.   "Kill the process made by the \\[compile] command."
  242.   (interactive)
  243.   (let ((compilation-process (get-buffer-process compilation-buffer-name)))
  244.     (if compilation-process
  245.     (interrupt-process compilation-process))))
  246.  
  247. (defun kill-grep ()
  248.   "Kill the process made by the \\[grep] command."
  249.   (interactive)
  250.   (let ((compilation-process (get-buffer-process grep-buffer-name)))
  251.     (if compilation-process
  252.     (interrupt-process compilation-process))))
  253.  
  254. (defun next-error (&optional argp)
  255.   "Visit next compilation error message and corresponding source code.
  256. This operates on the output from the \\[compile] and \\[grep] commands.
  257. The output from the last started compile or grep is processed unless
  258. you explicitly change the buffer to parse from with 
  259. \\[set-compilation-buffer].
  260. If all preparsed error messages have been processed,
  261. the error message buffer is checked for new ones.
  262. A non-nil argument (prefix arg, if interactive)
  263. means reparse the error message buffer and start at the first error."
  264.   (interactive "P")
  265.   (if (or (eq compilation-error-list t)
  266.       argp)
  267.       (progn (compilation-forget-errors)
  268.          (setq compilation-parsing-end 1)))
  269.   (if compilation-error-list
  270.       nil
  271.     (save-excursion
  272.       (switch-to-buffer last-compilation-buffer)
  273.       (set-buffer-modified-p nil)
  274.       (compilation-parse-errors)))
  275.   (let ((next-error (car compilation-error-list))
  276.     (compilation-process (get-buffer-process last-compilation-buffer)))
  277.     (if (null next-error)
  278.     (error (concat compilation-error-message
  279.                (if (and compilation-process
  280.                 (eq (process-status compilation-process)
  281.                     'run))
  282.                " yet" ""))))
  283.     (setq compilation-error-list (cdr compilation-error-list))
  284.     (if (null (car (cdr next-error)))
  285.     nil
  286.       (switch-to-buffer (marker-buffer (car (cdr next-error))))
  287.       (goto-char (car (cdr next-error)))
  288.       (set-marker (car (cdr next-error)) nil))
  289.     (let* ((pop-up-windows t)
  290.        (w (display-buffer (marker-buffer (car next-error)))))
  291.       (set-window-point w (car next-error))
  292.       (set-window-start w (car next-error)))
  293.     (set-marker (car next-error) nil)))
  294.  
  295. ;; Set compilation-error-list to nil, and
  296. ;; unchain the markers that point to the error messages and their text,
  297. ;; so that they no longer slow down gap motion.
  298. ;; This would happen anyway at the next garbage collection,
  299. ;; but it is better to do it right away.
  300. (defun compilation-forget-errors ()
  301.   (if (eq compilation-error-list t)
  302.       (setq compilation-error-list nil))
  303.   (if compilation-parsing-continue
  304.       (progn (set-marker (car (cdr compilation-parsing-continue)) nil)
  305.          (setq compilation-parsing-continue nil)))
  306.   (while compilation-error-list
  307.     (let ((next-error (car compilation-error-list)))
  308.       (set-marker (car next-error) nil)
  309.       (if (car (cdr next-error))
  310.       (set-marker (car (cdr next-error)) nil)))
  311.     (setq compilation-error-list (cdr compilation-error-list))))
  312.  
  313. (defun compilation-parse-errors ()
  314.   "Parse the current buffer as error messages.
  315. This makes a list of error descriptors, compilation-error-list.
  316. For each source-file, line-number pair in the buffer, the source file
  317. is read in, and the text location is saved in compilation-error-list.
  318. The function next-error, assigned to \\[next-error], takes the next
  319. error off the list and visits its location."
  320.   (setq compilation-error-list nil)
  321.   (message "Parsing error messages...")
  322.   (let (text-buffer
  323.     last-filename last-linenum)
  324.     ;; Don't reparse messages already seen at last parse.
  325.     (goto-char compilation-parsing-end)
  326.     ;; Continue parsing from last parsed buffer if any
  327.     (if compilation-parsing-continue
  328.     (save-excursion
  329.       (set-buffer
  330.        (setq text-buffer
  331.          (marker-buffer (car (cdr compilation-parsing-continue)))))
  332.       (setq last-filename (car (cdr (cdr compilation-parsing-continue))))
  333.       (setq last-linenum (car compilation-parsing-continue))
  334.       (goto-char (car (cdr compilation-parsing-continue)))
  335.       (set-marker (car (cdr compilation-parsing-continue)) nil)
  336.       (setq compilation-parsing-continue nil)))
  337.     ;; Don't parse the first two lines as error messages.
  338.     ;; This matters for grep.
  339.     (if (bobp)
  340.     (forward-line 2))
  341.     (while (re-search-forward compilation-error-regexp nil t)
  342.       (let (linenum filename
  343.         error-marker text-marker)
  344.     ;; Extract file name and line number from error message.
  345.     (save-restriction
  346.       (narrow-to-region (match-beginning 0) (match-end 0))
  347.       (goto-char (point-max))
  348.       (skip-chars-backward "[0-9]")
  349.       ;; If it's a lint message, use the last file(linenum) on the line.
  350.       ;; Normally we use the first on the line.
  351.       (if (= (preceding-char) ?\()
  352.           (progn
  353.         (narrow-to-region (point-min) (1+ (buffer-size)))
  354.         (end-of-line)
  355.         (re-search-backward compilation-error-regexp)
  356.         (skip-chars-backward "^ \t\n")
  357.         (narrow-to-region (point) (match-end 0))
  358.         (goto-char (point-max))
  359.         (skip-chars-backward "[0-9]")))
  360.       ;; Are we looking at a "filename-first" or "line-number-first" form?
  361.       (if (looking-at "[0-9]")
  362.           (progn
  363.         (setq linenum (read (current-buffer)))
  364.         (goto-char (point-min)))
  365.         ;; Line number at start, file name at end.
  366.         (progn
  367.           (goto-char (point-min))
  368.           (setq linenum (read (current-buffer)))
  369.           (goto-char (point-max))
  370.           (skip-chars-backward "^ \t\n")))
  371.       (setq filename (compilation-grab-filename)))
  372.     ;; Locate the erring file and line.
  373.     (if (and (equal filename last-filename)
  374.          (= linenum last-linenum))
  375.         nil
  376.       (beginning-of-line 1)
  377.       (setq error-marker (point-marker))
  378.       ;; text-buffer gets the buffer containing this error's file.
  379.       (if (not (equal filename last-filename))
  380.           (setq text-buffer
  381.             (and (file-exists-p (setq last-filename filename))
  382.              (find-file-noselect filename))
  383.             last-linenum 0))
  384.       (if text-buffer
  385.           ;; Go to that buffer and find the erring line.
  386.           (save-excursion
  387.         (set-buffer text-buffer)
  388.         (if (zerop last-linenum)
  389.             (progn
  390.               (goto-char 1)
  391.               (setq last-linenum 1)))
  392.         (forward-line (- linenum last-linenum))
  393.         (setq last-linenum linenum)
  394.         (setq text-marker (point-marker))
  395.         (setq compilation-error-list
  396.               (cons (list error-marker text-marker)
  397.                 compilation-error-list)))))
  398.     (forward-line 1)))
  399.     (if text-buffer
  400.     (setq compilation-parsing-continue
  401.           (list last-linenum
  402.             (save-excursion
  403.               (set-buffer text-buffer)
  404.               (point-marker))
  405.             last-filename)))
  406.     (setq compilation-parsing-end (point-max)))
  407.   (message "Parsing error messages...done")
  408.   (setq compilation-error-list (nreverse compilation-error-list)))
  409.  
  410. (defun compilation-grab-filename ()
  411.   "Return a string which is a filename, starting at point.
  412. Ignore quotes and parentheses around it, as well as trailing colons."
  413.   (if (eq (following-char) ?\")
  414.       (save-restriction
  415.     (narrow-to-region (point)
  416.               (progn (forward-sexp 1) (point)))
  417.     (goto-char (point-min))
  418.     (read (current-buffer)))
  419.     (buffer-substring (point)
  420.               (progn
  421.             (skip-chars-forward "^ :,\n\t(")
  422.             (point)))))
  423.  
  424. (define-key ctl-x-map "`" 'next-error)
  425.  
  426. (defun set-compilation-buffer (buffer)
  427.  "Sets the buffer to parse with \\[next-error]."
  428.  (interactive "bParsing from buffer:")
  429.  (compilation-forget-errors)
  430.  (setq compilation-parsing-end 1)
  431.  (setq last-compilation-buffer (get-buffer buffer))
  432.  (message "Dir is %s" (save-excursion
  433.             (set-buffer buffer)
  434.             default-directory)))
  435.  
  436. (load-file "GNU:emacs/lisp/compile-ok.el")
  437.  
  438.  
  439.  
  440. ----------------------------------------------------------------------------
  441. compile-ok.el
  442. ----------------------------------------------------------------------------
  443.  
  444. ;;; The idea is to depend more on regexps.
  445. ;;;
  446. (defvar compilation-all-error-types-regexps
  447.   '(("\\([^\n\t ]*\\):\\([0-9]+\\):.*\n" ((filename 1) (lineno 2))) ;; Common
  448.     ("\\([^\n\t ]*\\) \\([0-9]+\\) \\(Error\\|Warning\\).*\n" ;; SAS 6.0 Amiga
  449.      ((filename 1) (lineno 2))))
  450.   "Regexp variable that contains all possible error types.")
  451.  
  452.  
  453. (defun compilation-parse-errors ()
  454.   "Parse the current buffer as error messages.
  455. This makes a list of error descriptors, compilation-error-list.
  456. For each source-file, line-number pair in the buffer, the source file
  457. is read in, and the text location is saved in compilation-error-list.
  458. The function next-error, assigned to \\[next-error], takes the next
  459. error off the list and visits its location."
  460.   (setq compilation-error-list nil)
  461.   (message "Parsing error messages...")
  462.   (let (text-buffer
  463.     last-filename last-linenum)
  464.     ;; Don't reparse messages already seen at last parse.
  465.     (goto-char compilation-parsing-end)
  466.     ;; Continue parsing from last parsed buffer if any
  467.     (if compilation-parsing-continue
  468.     (save-excursion
  469.       (set-buffer
  470.        (setq text-buffer
  471.          (marker-buffer (car (cdr compilation-parsing-continue)))))
  472.       (setq last-filename (car (cdr (cdr compilation-parsing-continue))))
  473.       (setq last-linenum (car compilation-parsing-continue))
  474.       (goto-char (car (cdr compilation-parsing-continue)))
  475.       (set-marker (car (cdr compilation-parsing-continue)) nil)
  476.       (setq compilation-parsing-continue nil)))
  477.     ;; Don't parse the first two lines as error messages.
  478.     ;; This matters for grep.
  479.     (if (bobp)
  480.     (forward-line 2))
  481.     (while (not (eobp))
  482.       (let* (linenum filename
  483.          error-marker text-marker
  484.          (iamnow (point))
  485.          (list (sort (mapcar (function (lambda (ele)
  486.                        (goto-char iamnow)
  487.                        (cons
  488.                     (if (re-search-forward (car ele) nil t)
  489.                         (cons (match-beginning 0)
  490.                           (match-data))
  491.                       (cons (1+ (point-max))
  492.                         (match-data)))
  493.                     ele)))
  494.                  compilation-all-error-types-regexps)
  495.              (function (lambda (ele1 ele2)
  496.                      (< (car (car ele1)) (car (car ele2)))))))
  497.          (ele (car list))
  498.          lineno filename)
  499.     (if (and ele (car ele) (<= (car (car ele)) (point-max)))
  500.         (progn
  501.           (setq lineno (car (cdr (assoc 'lineno (car (cdr (cdr ele)))))))
  502.           (setq filename
  503.             (car (cdr (assoc 'filename (car (cdr (cdr ele)))))))
  504.           
  505.           ;; Extract file name and line number from error message.
  506.           (save-restriction
  507.         (store-match-data (cdr (car ele)))
  508.         (narrow-to-region (match-beginning lineno) (match-end lineno))
  509.         (goto-char (point-min))
  510.         (setq linenum (read (current-buffer)))
  511.         (widen)
  512.         (setq filename (buffer-substring (match-beginning filename)
  513.                          (match-end filename))))
  514.           ;; Locate the erring file and line.
  515.           (if (and (equal filename last-filename)
  516.                (= linenum last-linenum))
  517.           nil
  518.         (goto-char (match-beginning 0))
  519.         (setq error-marker (point-marker))
  520.         ;; text-buffer gets the buffer containing this error's file.
  521.         (if (not (equal filename last-filename))
  522.             (setq text-buffer
  523.               (and (file-exists-p (setq last-filename filename))
  524.                    (find-file-noselect filename))
  525.               last-linenum 0))
  526.         (if text-buffer
  527.             ;; Go to that buffer and find the erring line.
  528.             (save-excursion
  529.               (set-buffer text-buffer)
  530.               (if (zerop last-linenum)
  531.               (progn
  532.                 (goto-char 1)
  533.                 (setq last-linenum 1)))
  534.               (forward-line (- linenum last-linenum))
  535.               (setq last-linenum linenum)
  536.               (setq text-marker (point-marker))
  537.               (setq compilation-error-list
  538.                 (cons (list error-marker text-marker)
  539.                   compilation-error-list)))))
  540.           (goto-char (match-end 0)))
  541.       (goto-char (point-max)))))
  542.     (if text-buffer
  543.     (setq compilation-parsing-continue
  544.           (list last-linenum
  545.             (save-excursion
  546.               (set-buffer text-buffer)
  547.               (point-marker))
  548.             last-filename)))
  549.     (setq compilation-parsing-end (point-max)))
  550.   (message "Parsing error messages...done")
  551.   (setq compilation-error-list (nreverse compilation-error-list)))
  552.