;; -*- mode: emacs-lisp  -*-
;;
;; asir-mode.el -- asir mode
;;
;; $OpenXM: OpenXM_contrib2/windows/post-msg-asirgui/asir-mode.el,v 1.15 2021/02/24 23:10:32 takayama Exp $

;; 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 of the License, or
;; (at your option) any later version.

;; 1. Install 
;;
;; **(for Windows) Write the following configuration to your .emacs file.
;;
;; (setq load-path (append load-path '((concat (getenv "ASIR_ROOTDIR") "/share/editor"))))
;; (setq auto-mode-alist (cons '("\\.rr$" . asir-mode) auto-mode-alist))
;; (autoload 'asir-mode "asir-mode" "Asir mode" t)
;;
;; **(for unix) Copy this file to your emacs site-lisp folder and 
;;              write the following configuration to your .emacs file.
;;
;; (setq auto-mode-alist (cons '("\\.rr$" . asir-mode) auto-mode-alist))
;; (autoload 'asir-mode "asir-mode" "Asir mode" t)
;;
;; Please run byte-compile for speed up.
;;
;; 2. Use
;;
;; If you open Risa/Asir source file (*.rr) by emacs, then asir-mode starts up automatically.
;; The following key binding can be used:
;; C-c s     Asir starts up in another window.
;; C-c t     Asir terminates.
;; C-c a     Abort current calculation.
;; C-c l     The current buffer is loaded to Asir as a file.
;; C-c r     Selected region is loaded to Asir as a file.
;; C-c p     Selected region is pasted to Asir.

(require 'shell)
(require 'cl)

;;;; AsirGUI for Windows
(defvar asir-exec-path '("~/Desktop/asir/bin" "c:/Program Files/asir/bin" "c:/Program Files (x64)/asir/bin" "c:/asir/bin")
  "Default search path for asir binary in Windows")

(defun asir-effective-exec-path ()
  "Search path for command"
  (let* ((dir (getenv "ASIR_ROOTDIR"))
         (path (append asir-exec-path exec-path)))
    (if dir (cons (concat dir "/bin") path) path)))

(defun asir-executable-find (command)
  "Search for command"
  (let* ((exec-path (asir-effective-exec-path)))
    (executable-find command)))

;;;; Asir for UNIX
(defvar asir-cmd-buffer-name "*asir-cmd*")

(defun asir-cmd-load (filename)
  "Send `load' command to running asir process"
  (if (eq system-type 'windows-nt)
      (let ((exec-path (asir-effective-exec-path)))
        (start-process "asir-proc-cmdasir" nil "cmdasir" filename))
    (save-excursion
      (if (get-buffer asir-cmd-buffer-name)
          (progn
            (set-buffer asir-cmd-buffer-name)
            (goto-char (point-max))
            (insert (format "load(\"%s\");" filename))
            (comint-send-input))))))

(defun asir-start ()
  "Start asir process"
  (interactive)
  (if (eq system-type 'windows-nt)
    ;; for Windows
      (let ((exec-path (asir-effective-exec-path)))
        (start-process "asir-proc-asirgui" nil "asirgui"))
    ;; for UNIX
    (save-excursion
      (if (not (get-buffer asir-cmd-buffer-name))
          (let ((current-frame (selected-frame)))
            (if window-system 
                (progn 
                  (select-frame (make-frame))
                  (shell (get-buffer-create asir-cmd-buffer-name)) ;; Switch to new buffer automatically
                  (delete-other-windows))
              (if (>= emacs-major-version 24)
                  (progn 
                    (split-window)
                    (other-window -1)))
              (shell (get-buffer-create asir-cmd-buffer-name)))
            (sleep-for 1)
            (goto-char (point-max))
            (insert "openxm asir -nofep")
            (comint-send-input)
            (select-frame current-frame))))))

(defun asir-terminate ()
  "Terminate asir process"
  (interactive)
  (if (eq system-type 'windows-nt)
    ;; for Windows
      (let ((exec-path (asir-effective-exec-path)))
        (start-process "asir-proc-cmdasir" nil "cmdasir" "--quit"))
    ;; for UNIX
    (if (get-buffer asir-cmd-buffer-name)
        (if (not window-system)
            (let ((asir-cmd-window (get-buffer-window asir-cmd-buffer-name)))
              (and (kill-buffer asir-cmd-buffer-name)
                   (or (not asir-cmd-window) (delete-window asir-cmd-window))))
          (let ((asir-cmd-frame (window-frame (get-buffer-window asir-cmd-buffer-name 0))))
            (and (kill-buffer asir-cmd-buffer-name)
                 (delete-frame asir-cmd-frame)))))))

(defun asir-execute-current-buffer ()
  "Execute current buffer on asir"
  (interactive)
  (let ((exec-path (asir-effective-exec-path)))
    (asir-cmd-load (buffer-file-name))))

(defun asir-execute-region ()
  "Execute region on asir"
  (interactive)
  (if mark-active
      (save-excursion
        (let ((temp-file (make-temp-file (format "%s/cmdasir-" (or (getenv "TEMP") "/var/tmp"))))
              (temp-buffer (generate-new-buffer " *asir-temp*")))
          (write-region (region-beginning) (region-end) temp-file)
          (set-buffer temp-buffer)
          (insert " end$")
          (write-region (point-min) (point-max) temp-file t) ;; append
          (kill-buffer temp-buffer)
          (asir-cmd-load temp-file)))))

(defun asir-paste-region ()
  "Paste region to asir"
  (interactive)
  (if mark-active
      (if (eq system-type 'windows-nt)
          (let ((temp-file (make-temp-file (format "%s/cmdasir-" (getenv "TEMP"))))
                (exec-path (asir-effective-exec-path)))
            (write-region (region-beginning) (region-end) temp-file)
            (start-process "asir-proc-cmdasir" nil "cmdasir" "--paste-contents" temp-file))
        (save-excursion
          (let ((buffer (current-buffer))
                (start (region-beginning))
                (end (region-end)))
            (set-buffer asir-cmd-buffer-name)
            (goto-char (point-max))
            (insert-buffer-substring buffer start end)
            (comint-send-input))))))

(defun asir-abort ()
  "Abort calculation on asir"
  (interactive)
  (if (eq system-type 'windows-nt)
    ;; for Windows
      (let ((exec-path (asir-effective-exec-path)))
        (start-process "asir-proc-cmdasir" nil "cmdasir" "--abort"))
    ;; for UNIX
    (save-excursion
      (if (get-buffer asir-cmd-buffer-name)
          (progn
            (set-buffer asir-cmd-buffer-name)
            (comint-kill-input)
            (comint-interrupt-subjob)
            (goto-char (point-max))
            (insert "t\ny")
            (comint-send-input)
            )))))

;;;; Extension for CC-mode.

(require 'cc-mode)

(eval-when-compile
  (require 'cc-langs)
  (require 'cc-engine)
  (require 'cc-fonts))

(eval-and-compile
  ;; Make our mode known to the language constant system.  Use Java
  ;; mode as the fallback for the constants we don't change here.
  ;; This needs to be done also at compile time since the language
  ;; constants are evaluated then.
  (c-add-language 'asir-mode 'c++-mode))

(c-lang-defconst c-stmt-delim-chars asir "^;${}?:")
(c-lang-defconst c-stmt-delim-chars-with-comma asir "^;$,{}?:")
(c-lang-defconst c-other-op-syntax-tokens 
  asir (cons "$" (c-lang-const c-other-op-syntax-tokens c)))
(c-lang-defconst c-identifier-syntax-modifications 
  asir (remove '(?$ . "w") (c-lang-const c-identifier-syntax-modifications c)))
(c-lang-defconst c-symbol-chars asir (concat c-alnum "_"))

(c-lang-defconst c-primitive-type-kwds asir '("def" "extern" "static" "localf" "function"))
(c-lang-defconst c-primitive-type-prefix-kwds asir nil)
(c-lang-defconst c-type-list-kwds asir nil)
(c-lang-defconst c-class-decl-kwds asir '("module"))
(c-lang-defconst c-othe-decl-kwds  asir '("endmodule" "end"))
(c-lang-defconst c-type-modifier-kwds asir nil)
(c-lang-defconst c-modifier-kwds asir nil)

(c-lang-defconst c-mode-menu 
  asir
  (append (c-lang-const c-mode-menu c)
		  '("----" 
			["Start Asir" asir-start t]
			["Terminate Asir" asir-terminate t]
			["Abort calcuration on Asir" asir-abort t]
			["Execute Current Buffer on Asir" asir-execute-current-buffer (buffer-file-name)]
			["Execute Region on Asir" asir-execute-region mark-active]
			["Paste Region to Asir" asir-paste-region mark-active]
			)))

(defvar asir-font-lock-extra-types nil
  "*List of extra types (aside from the type keywords) to recognize in asir mode.
Each list item should be a regexp matching a single identifier.")

(defconst asir-font-lock-keywords-1 (c-lang-const c-matchers-1 asir)
  "Minimal highlighting for asir mode.")

(defconst asir-font-lock-keywords-2 (c-lang-const c-matchers-2 asir)
  "Fast normal highlighting for asir mode.")

(defconst asir-font-lock-keywords-3 (c-lang-const c-matchers-3 asir)
  "Accurate normal highlighting for asir mode.")

(defvar asir-font-lock-keywords asir-font-lock-keywords-3
  "Default expressions to highlight in asir mode.")

(defvar asir-mode-syntax-table nil
  "Syntax table used in asir-mode buffers.")
(or asir-mode-syntax-table
    (setq asir-mode-syntax-table
	  (funcall (c-lang-const c-make-mode-syntax-table asir))))

(defvar asir-mode-abbrev-table nil
  "Abbreviation table used in asir-mode buffers.")

(defvar asir-mode-map (let ((map (c-make-inherited-keymap)))
		      ;; Add bindings which are only useful for asir
		      map)
  "Keymap used in asir-mode buffers.")

;; Key binding for asir-mode
(define-key asir-mode-map (kbd "C-c s") 'asir-start)
(define-key asir-mode-map (kbd "C-c t") 'asir-terminate)
(define-key asir-mode-map (kbd "C-c a") 'asir-abort)
(define-key asir-mode-map (kbd "C-c l") 'asir-execute-current-buffer)
(define-key asir-mode-map (kbd "C-c r") 'asir-execute-region)
(define-key asir-mode-map (kbd "C-c p") 'asir-paste-region)

(easy-menu-define asir-menu asir-mode-map "asir Mode Commands"
		  ;; Can use `asir' as the language for `c-mode-menu'
		  ;; since its definition covers any language.  In
		  ;; this case the language is used to adapt to the
		  ;; nonexistence of a cpp pass and thus removing some
		  ;; irrelevant menu alternatives.
		  (cons "Asir" (c-lang-const c-mode-menu asir)))

(defun asir-mode ()
  "Major mode for editing asir code.
This is a simple example of a separate mode derived from CC Mode to
support a language with syntax similar to C/C++/ObjC/Java/IDL/Pike.

The hook `c-mode-common-hook' is run with no args at mode
initialization, then `asir-mode-hook'.

Key bindings:
\\{asir-mode-map}"
  (interactive)
  (kill-all-local-variables)
  (c-initialize-cc-mode t)
  (set-syntax-table asir-mode-syntax-table)
  (setq major-mode 'asir-mode
	mode-name "asir"
	local-abbrev-table asir-mode-abbrev-table
	abbrev-mode t)
  (use-local-map asir-mode-map)
  ;; `c-init-language-vars' is a macro that is expanded at compile
  ;; time to a large `setq' with all the language variables and their
  ;; customized values for our language.
  (c-init-language-vars asir-mode)
  ;; `c-common-init' initializes most of the components of a CC Mode
  ;; buffer, including setup of the mode menu, font-lock, etc.
  ;; There's also a lower level routine `c-basic-common-init' that
  ;; only makes the necessary initialization to get the syntactic
  ;; analysis and similar things working.
  (c-common-init 'asir-mode)
;;(easy-menu-add asir-menu)
  (run-hooks 'c-mode-common-hook)
  (run-hooks 'asir-mode-hook)
  (c-update-modeline))

(if (fboundp 'asir-backup:c-guess-basic-syntax)
	nil
  (fset 'asir-backup:c-guess-basic-syntax (symbol-function 'c-guess-basic-syntax))
  (defun c-guess-basic-syntax ()
	"A modified c-guess-basic-syntax for asir-mode"
	(if (eq major-mode 'asir-mode)
		(asir-c-guess-basic-syntax)
	  (asir-backup:c-guess-basic-syntax))))

;; Meadow 3 does not have `c-brace-anchor-point'
;; This function was copied from cc-engine.el of Emacs 23.4
(if (and (featurep 'meadow) (not (fboundp 'c-brace-anchor-point)))
    (defun c-brace-anchor-point (bracepos)
      ;; BRACEPOS is the position of a brace in a construct like "namespace
      ;; Bar {".  Return the anchor point in this construct; this is the
      ;; earliest symbol on the brace's line which isn't earlier than
      ;; "namespace".
      ;;
      ;; Currently (2007-08-17), "like namespace" means "matches
      ;; c-other-block-decl-kwds".  It doesn't work with "class" or "struct"
      ;; or anything like that.
      (save-excursion
        (let ((boi (c-point 'boi bracepos)))
          (goto-char bracepos)
          (while (and (> (point) boi)
                      (not (looking-at c-other-decl-block-key)))
            (c-backward-token-2))
          (if (> (point) boi) (point) boi))))
  )

;; The function `c-guess-basic-syntax' was copied from cc-engine.el of Emacs 23.4 and 
;; was modified for Risa/Asir.
;; CASE 5D, 5J, 18 are corrected.

;;;; Beginning of `asir-c-guess-basic-syntax'
(defun asir-c-guess-basic-syntax ()
  "Return the syntactic context of the current line."
  (save-excursion
      (beginning-of-line)
      (c-save-buffer-state
	  ((indent-point (point))
	   (case-fold-search nil)
	   ;; A whole ugly bunch of various temporary variables.  Have
	   ;; to declare them here since it's not possible to declare
	   ;; a variable with only the scope of a cond test and the
	   ;; following result clauses, and most of this function is a
	   ;; single gigantic cond. :P
	   literal char-before-ip before-ws-ip char-after-ip macro-start
	   in-macro-expr c-syntactic-context placeholder c-in-literal-cache
	   step-type tmpsymbol keyword injava-inher special-brace-list tmp-pos
	   containing-<
	   ;; The following record some positions for the containing
	   ;; declaration block if we're directly within one:
	   ;; `containing-decl-open' is the position of the open
	   ;; brace.  `containing-decl-start' is the start of the
	   ;; declaration.  `containing-decl-kwd' is the keyword
	   ;; symbol of the keyword that tells what kind of block it
	   ;; is.
	   containing-decl-open
	   containing-decl-start
	   containing-decl-kwd
	   ;; The open paren of the closest surrounding sexp or nil if
	   ;; there is none.
	   containing-sexp
	   ;; The position after the closest preceding brace sexp
	   ;; (nested sexps are ignored), or the position after
	   ;; `containing-sexp' if there is none, or (point-min) if
	   ;; `containing-sexp' is nil.
	   lim
	   ;; The paren state outside `containing-sexp', or at
	   ;; `indent-point' if `containing-sexp' is nil.
	   (paren-state (c-parse-state))
	   ;; There's always at most one syntactic element which got
	   ;; an anchor pos.  It's stored in syntactic-relpos.
	   syntactic-relpos
	   (c-stmt-delim-chars c-stmt-delim-chars))

	;; Check if we're directly inside an enclosing declaration
	;; level block.
	(when (and (setq containing-sexp
			 (c-most-enclosing-brace paren-state))
		   (progn
		     (goto-char containing-sexp)
		     (eq (char-after) ?{))
		   (setq placeholder
			 (c-looking-at-decl-block
			  (c-most-enclosing-brace paren-state
						  containing-sexp)
			  t)))
	  (setq containing-decl-open containing-sexp
		containing-decl-start (point)
		containing-sexp nil)
	  (goto-char placeholder)
	  (setq containing-decl-kwd (and (looking-at c-keywords-regexp)
					 (c-keyword-sym (match-string 1)))))

	;; Init some position variables.
	(if c-state-cache
	    (progn
	      (setq containing-sexp (car paren-state)
		    paren-state (cdr paren-state))
	      (if (consp containing-sexp)
		  (progn
		    (setq lim (cdr containing-sexp))
		    (if (cdr c-state-cache)
			;; Ignore balanced paren.  The next entry
			;; can't be another one.
			(setq containing-sexp (car (cdr c-state-cache))
			      paren-state (cdr paren-state))
		      ;; If there is no surrounding open paren then
		      ;; put the last balanced pair back on paren-state.
		      (setq paren-state (cons containing-sexp paren-state)
			    containing-sexp nil)))
		(setq lim (1+ containing-sexp))))
	  (setq lim (point-min)))

	;; If we're in a parenthesis list then ',' delimits the
	;; "statements" rather than being an operator (with the
	;; exception of the "for" clause).  This difference is
	;; typically only noticeable when statements are used in macro
	;; arglists.
	(when (and containing-sexp
		   (eq (char-after containing-sexp) ?\())
	  (setq c-stmt-delim-chars c-stmt-delim-chars-with-comma))

	;; cache char before and after indent point, and move point to
	;; the most likely position to perform the majority of tests
	(goto-char indent-point)
	(c-backward-syntactic-ws lim)
	(setq before-ws-ip (point)
	      char-before-ip (char-before))
	(goto-char indent-point)
	(skip-chars-forward " \t")
	(setq char-after-ip (char-after))

	;; are we in a literal?
	(setq literal (c-in-literal lim))

	;; now figure out syntactic qualities of the current line
	(cond

	 ;; CASE 1: in a string.
	 ((eq literal 'string)
	  (c-add-syntax 'string (c-point 'bopl)))

	 ;; CASE 2: in a C or C++ style comment.
	 ((and (memq literal '(c c++))
	       ;; This is a kludge for XEmacs where we use
	       ;; `buffer-syntactic-context', which doesn't correctly
	       ;; recognize "\*/" to end a block comment.
	       ;; `parse-partial-sexp' which is used by
	       ;; `c-literal-limits' will however do that in most
	       ;; versions, which results in that we get nil from
	       ;; `c-literal-limits' even when `c-in-literal' claims
	       ;; we're inside a comment.
	       (setq placeholder (c-literal-limits lim)))
	  (c-add-syntax literal (car placeholder)))

	 ;; CASE 3: in a cpp preprocessor macro continuation.
	 ((and (save-excursion
		 (when (c-beginning-of-macro)
		   (setq macro-start (point))))
	       (/= macro-start (c-point 'boi))
	       (progn
		 (setq tmpsymbol 'cpp-macro-cont)
		 (or (not c-syntactic-indentation-in-macros)
		     (save-excursion
		       (goto-char macro-start)
		       ;; If at the beginning of the body of a #define
		       ;; directive then analyze as cpp-define-intro
		       ;; only.  Go on with the syntactic analysis
		       ;; otherwise.  in-macro-expr is set if we're in a
		       ;; cpp expression, i.e. before the #define body
		       ;; or anywhere in a non-#define directive.
		       (if (c-forward-to-cpp-define-body)
			   (let ((indent-boi (c-point 'boi indent-point)))
			     (setq in-macro-expr (> (point) indent-boi)
				   tmpsymbol 'cpp-define-intro)
			     (= (point) indent-boi))
			 (setq in-macro-expr t)
			 nil)))))
	  (c-add-syntax tmpsymbol macro-start)
	  (setq macro-start nil))

	 ;; CASE 11: an else clause?
	 ((looking-at "else\\>[^_]")
	  (c-beginning-of-statement-1 containing-sexp)
	  (c-add-stmt-syntax 'else-clause nil t
			     containing-sexp paren-state))

	 ;; CASE 12: while closure of a do/while construct?
	 ((and (looking-at "while\\>[^_]")
	       (save-excursion
		 (prog1 (eq (c-beginning-of-statement-1 containing-sexp)
			    'beginning)
		   (setq placeholder (point)))))
	  (goto-char placeholder)
	  (c-add-stmt-syntax 'do-while-closure nil t
			     containing-sexp paren-state))

	 ;; CASE 13: A catch or finally clause?  This case is simpler
	 ;; than if-else and do-while, because a block is required
	 ;; after every try, catch and finally.
	 ((save-excursion
	    (and (cond ((c-major-mode-is 'c++-mode)
			(looking-at "catch\\>[^_]"))
		       ((c-major-mode-is 'java-mode)
			(looking-at "\\(catch\\|finally\\)\\>[^_]")))
		 (and (c-safe (c-backward-syntactic-ws)
			      (c-backward-sexp)
			      t)
		      (eq (char-after) ?{)
		      (c-safe (c-backward-syntactic-ws)
			      (c-backward-sexp)
			      t)
		      (if (eq (char-after) ?\()
			  (c-safe (c-backward-sexp) t)
			t))
		 (looking-at "\\(try\\|catch\\)\\>[^_]")
		 (setq placeholder (point))))
	  (goto-char placeholder)
	  (c-add-stmt-syntax 'catch-clause nil t
			     containing-sexp paren-state))

	 ;; CASE 18: A substatement we can recognize by keyword.
	 ((save-excursion
	    (and c-opt-block-stmt-key
		 (not (eq char-before-ip ?\;))
		 (not (c-at-vsemi-p before-ws-ip))
		 (not (memq char-after-ip '(?\) ?\] ?,)))
		 (or (not (eq char-before-ip ?}))
		     (c-looking-at-inexpr-block-backward c-state-cache))
		 (> (point)
		    (progn
		      ;; Ought to cache the result from the
		      ;; c-beginning-of-statement-1 calls here.
		      (setq placeholder (point))
		      (while (eq (setq step-type
				       (c-beginning-of-statement-1 lim))
				 'label))
		      (if (eq step-type 'previous)
			  (goto-char placeholder)
			(setq placeholder (point))
			(if (and (eq step-type 'same)
				 (not (looking-at c-opt-block-stmt-key)))
			    ;; Step up to the containing statement if we
			    ;; stayed in the same one.
			    (let (step)
			      (while (eq
				      (setq step
					    (c-beginning-of-statement-1 lim))
				      'label))
			      (if (eq step 'up)
				  (setq placeholder (point))
				;; There was no containing statement after all.
				(goto-char placeholder)))))
		      placeholder))
		 (if (looking-at c-block-stmt-2-key)
		     ;; Require a parenthesis after these keywords.
		     ;; Necessary to catch e.g. synchronized in Java,
		     ;; which can be used both as statement and
		     ;; modifier.
		     (and (zerop (c-forward-token-2 1 nil))
			  (eq (char-after) ?\())
		   (looking-at c-opt-block-stmt-key))))

	  (if (eq step-type 'up)
	      ;; CASE 18A: Simple substatement.
	      (progn
		(goto-char placeholder)
		(cond
		 ((eq char-after-ip ?{)
		  (c-add-stmt-syntax 'substatement-open nil nil
				     containing-sexp paren-state))
		 ((save-excursion
		    (goto-char indent-point)
		    (back-to-indentation)
		    (c-forward-label))
		  (c-add-stmt-syntax 'substatement-label nil nil
				     containing-sexp paren-state))
		 (t
		  (c-add-stmt-syntax 'substatement nil nil
				     containing-sexp paren-state))))

	    ;; CASE 18B: Some other substatement.  This is shared
	    ;; with case 10.
	    (c-guess-continued-construct indent-point
					 char-after-ip
					 placeholder
					 lim
					 paren-state)))

	 ;; CASE 14: A case or default label
	 ((looking-at c-label-kwds-regexp)
	  (if containing-sexp
	      (progn
		(goto-char containing-sexp)
		(setq lim (c-most-enclosing-brace c-state-cache
						  containing-sexp))
		(c-backward-to-block-anchor lim)
		(c-add-stmt-syntax 'case-label nil t lim paren-state))
	    ;; Got a bogus label at the top level.  In lack of better
	    ;; alternatives, anchor it on (point-min).
	    (c-add-syntax 'case-label (point-min))))

	 ;; CASE 15: any other label
	 ((save-excursion
	    (back-to-indentation)
	    (and (not (looking-at c-syntactic-ws-start))
		 (c-forward-label)))
	  (cond (containing-decl-open
		 (setq placeholder (c-add-class-syntax 'inclass
						       containing-decl-open
						       containing-decl-start
						       containing-decl-kwd
						       paren-state))
		 ;; Append access-label with the same anchor point as
		 ;; inclass gets.
		 (c-append-syntax 'access-label placeholder))

		(containing-sexp
		 (goto-char containing-sexp)
		 (setq lim (c-most-enclosing-brace c-state-cache
						   containing-sexp))
		 (save-excursion
		   (setq tmpsymbol
			 (if (and (eq (c-beginning-of-statement-1 lim) 'up)
				  (looking-at "switch\\>[^_]"))
			     ;; If the surrounding statement is a switch then
			     ;; let's analyze all labels as switch labels, so
			     ;; that they get lined up consistently.
			     'case-label
			   'label)))
		 (c-backward-to-block-anchor lim)
		 (c-add-stmt-syntax tmpsymbol nil t lim paren-state))

		(t
		 ;; A label on the top level.  Treat it as a class
		 ;; context.  (point-min) is the closest we get to the
		 ;; class open brace.
		 (c-add-syntax 'access-label (point-min)))))

	 ;; CASE 4: In-expression statement.  C.f. cases 7B, 16A and
	 ;; 17E.
	 ((setq placeholder (c-looking-at-inexpr-block
			     (c-safe-position containing-sexp paren-state)
			     containing-sexp
			     ;; Have to turn on the heuristics after
			     ;; the point even though it doesn't work
			     ;; very well.  C.f. test case class-16.pike.
			     t))
	  (setq tmpsymbol (assq (car placeholder)
				'((inexpr-class . class-open)
				  (inexpr-statement . block-open))))
	  (if tmpsymbol
	      ;; It's a statement block or an anonymous class.
	      (setq tmpsymbol (cdr tmpsymbol))
	    ;; It's a Pike lambda.  Check whether we are between the
	    ;; lambda keyword and the argument list or at the defun
	    ;; opener.
	    (setq tmpsymbol (if (eq char-after-ip ?{)
				'inline-open
			      'lambda-intro-cont)))
	  (goto-char (cdr placeholder))
	  (back-to-indentation)
	  (c-add-stmt-syntax tmpsymbol nil t
			     (c-most-enclosing-brace c-state-cache (point))
			     paren-state)
	  (unless (eq (point) (cdr placeholder))
	    (c-add-syntax (car placeholder))))

	 ;; CASE 5: Line is inside a declaration level block or at top level.
	 ((or containing-decl-open (null containing-sexp))
	  (cond

	   ;; CASE 5A: we are looking at a defun, brace list, class,
	   ;; or inline-inclass method opening brace
	   ((setq special-brace-list
		  (or (and c-special-brace-lists
			   (c-looking-at-special-brace-list))
		      (eq char-after-ip ?{)))
	    (cond

	     ;; CASE 5A.1: Non-class declaration block open.
	     ((save-excursion
		(let (tmp)
		  (and (eq char-after-ip ?{)
		       (setq tmp (c-looking-at-decl-block containing-sexp t))
		       (progn
			 (setq placeholder (point))
			 (goto-char tmp)
			 (looking-at c-symbol-key))
		       (c-keyword-member
			(c-keyword-sym (setq keyword (match-string 0)))
			'c-other-block-decl-kwds))))
	      (goto-char placeholder)
	      (c-add-stmt-syntax
	       (if (string-equal keyword "extern")
		   ;; Special case for extern-lang-open.
		   'extern-lang-open
		 (intern (concat keyword "-open")))
	       nil t containing-sexp paren-state))

	     ;; CASE 5A.2: we are looking at a class opening brace
	     ((save-excursion
		(goto-char indent-point)
		(skip-chars-forward " \t")
		(and (eq (char-after) ?{)
		     (c-looking-at-decl-block containing-sexp t)
		     (setq placeholder (point))))
	      (c-add-syntax 'class-open placeholder))

	     ;; CASE 5A.3: brace list open
	     ((save-excursion
		(c-beginning-of-decl-1 lim)
		(while (looking-at c-specifier-key)
		  (goto-char (match-end 1))
		  (c-forward-syntactic-ws indent-point))
		(setq placeholder (c-point 'boi))
		(or (consp special-brace-list)
		    (and (or (save-excursion
			       (goto-char indent-point)
			       (setq tmpsymbol nil)
			       (while (and (> (point) placeholder)
					   (zerop (c-backward-token-2 1 t))
					   (/= (char-after) ?=))
				 (and c-opt-inexpr-brace-list-key
				      (not tmpsymbol)
				      (looking-at c-opt-inexpr-brace-list-key)
				      (setq tmpsymbol 'topmost-intro-cont)))
			       (eq (char-after) ?=))
			     (looking-at c-brace-list-key))
			 (save-excursion
			   (while (and (< (point) indent-point)
				       (zerop (c-forward-token-2 1 t))
				       (not (memq (char-after) '(?\; ?\()))))
			   (not (memq (char-after) '(?\; ?\()))
			   ))))
	      (if (and (not c-auto-newline-analysis)
		       (c-major-mode-is 'java-mode)
		       (eq tmpsymbol 'topmost-intro-cont))
		  ;; We're in Java and have found that the open brace
		  ;; belongs to a "new Foo[]" initialization list,
		  ;; which means the brace list is part of an
		  ;; expression and not a top level definition.  We
		  ;; therefore treat it as any topmost continuation
		  ;; even though the semantically correct symbol still
		  ;; is brace-list-open, on the same grounds as in
		  ;; case B.2.
		  (progn
		    (c-beginning-of-statement-1 lim)
		    (c-add-syntax 'topmost-intro-cont (c-point 'boi)))
		(c-add-syntax 'brace-list-open placeholder)))

	     ;; CASE 5A.4: inline defun open
	     ((and containing-decl-open
		   (not (c-keyword-member containing-decl-kwd
					  'c-other-block-decl-kwds)))
	      (c-add-syntax 'inline-open)
	      (c-add-class-syntax 'inclass
				  containing-decl-open
				  containing-decl-start
				  containing-decl-kwd
				  paren-state))

	     ;; CASE 5A.5: ordinary defun open
	     (t
	      (save-excursion
		(c-beginning-of-decl-1 lim)
		(while (looking-at c-specifier-key)
		  (goto-char (match-end 1))
		  (c-forward-syntactic-ws indent-point))
		(c-add-syntax 'defun-open (c-point 'boi))
		;; Bogus to use bol here, but it's the legacy.  (Resolved,
		;; 2007-11-09)
		))))

	   ;; CASE 5B: After a function header but before the body (or
	   ;; the ending semicolon if there's no body).
	   ((save-excursion
	      (when (setq placeholder (c-just-after-func-arglist-p lim))
		(setq tmp-pos (point))))
	    (cond

	     ;; CASE 5B.1: Member init list.
	     ((eq (char-after tmp-pos) ?:)
	      (if (or (> tmp-pos indent-point)
		      (= (c-point 'bosws) (1+ tmp-pos)))
		  (progn
		    ;; There is no preceding member init clause.
		    ;; Indent relative to the beginning of indentation
		    ;; for the topmost-intro line that contains the
		    ;; prototype's open paren.
		    (goto-char placeholder)
		    (c-add-syntax 'member-init-intro (c-point 'boi)))
		;; Indent relative to the first member init clause.
		(goto-char (1+ tmp-pos))
		(c-forward-syntactic-ws)
		(c-add-syntax 'member-init-cont (point))))

	     ;; CASE 5B.2: K&R arg decl intro
	     ((and c-recognize-knr-p
		   (c-in-knr-argdecl lim))
	      (c-beginning-of-statement-1 lim)
	      (c-add-syntax 'knr-argdecl-intro (c-point 'boi))
	      (if containing-decl-open
		  (c-add-class-syntax 'inclass
				      containing-decl-open
				      containing-decl-start
				      containing-decl-kwd
				      paren-state)))

	     ;; CASE 5B.4: Nether region after a C++ or Java func
	     ;; decl, which could include a `throws' declaration.
	     (t
	      (c-beginning-of-statement-1 lim)
	      (c-add-syntax 'func-decl-cont (c-point 'boi))
	      )))

	   ;; CASE 5C: inheritance line. could be first inheritance
	   ;; line, or continuation of a multiple inheritance
	   ((or (and (c-major-mode-is 'c++-mode)
		     (progn
		       (when (eq char-after-ip ?,)
			 (skip-chars-forward " \t")
			 (forward-char))
		       (looking-at c-opt-postfix-decl-spec-key)))
		(and (or (eq char-before-ip ?:)
			 ;; watch out for scope operator
			 (save-excursion
			   (and (eq char-after-ip ?:)
				(c-safe (forward-char 1) t)
				(not (eq (char-after) ?:))
				)))
		     (save-excursion
		       (c-backward-syntactic-ws lim)
		       (if (eq char-before-ip ?:)
			   (progn
			     (forward-char -1)
			     (c-backward-syntactic-ws lim)))
		       (back-to-indentation)
		       (looking-at c-class-key)))
		;; for Java
		(and (c-major-mode-is 'java-mode)
		     (let ((fence (save-excursion
				    (c-beginning-of-statement-1 lim)
				    (point)))
			   cont done)
		       (save-excursion
			 (while (not done)
			   (cond ((looking-at c-opt-postfix-decl-spec-key)
				  (setq injava-inher (cons cont (point))
					done t))
				 ((or (not (c-safe (c-forward-sexp -1) t))
				      (<= (point) fence))
				  (setq done t))
				 )
			   (setq cont t)))
		       injava-inher)
		     (not (c-crosses-statement-barrier-p (cdr injava-inher)
							 (point)))
		     ))
	    (cond

	     ;; CASE 5C.1: non-hanging colon on an inher intro
	     ((eq char-after-ip ?:)
	      (c-beginning-of-statement-1 lim)
	      (c-add-syntax 'inher-intro (c-point 'boi))
	      ;; don't add inclass symbol since relative point already
	      ;; contains any class offset
	      )

	     ;; CASE 5C.2: hanging colon on an inher intro
	     ((eq char-before-ip ?:)
	      (c-beginning-of-statement-1 lim)
	      (c-add-syntax 'inher-intro (c-point 'boi))
	      (if containing-decl-open
		  (c-add-class-syntax 'inclass
				      containing-decl-open
				      containing-decl-start
				      containing-decl-kwd
				      paren-state)))

	     ;; CASE 5C.3: in a Java implements/extends
	     (injava-inher
	      (let ((where (cdr injava-inher))
		    (cont (car injava-inher)))
		(goto-char where)
		(cond ((looking-at "throws\\>[^_]")
		       (c-add-syntax 'func-decl-cont
				     (progn (c-beginning-of-statement-1 lim)
					    (c-point 'boi))))
		      (cont (c-add-syntax 'inher-cont where))
		      (t (c-add-syntax 'inher-intro
				       (progn (goto-char (cdr injava-inher))
					      (c-beginning-of-statement-1 lim)
					      (point))))
		      )))

	     ;; CASE 5C.4: a continued inheritance line
	     (t
	      (c-beginning-of-inheritance-list lim)
	      (c-add-syntax 'inher-cont (point))
	      ;; don't add inclass symbol since relative point already
	      ;; contains any class offset
	      )))

	   ;; CASE 5D: this could be a top-level initialization, a
	   ;; member init list continuation, or a template argument
	   ;; list continuation.
	   ((save-excursion
	      ;; Note: We use the fact that lim is always after any
	      ;; preceding brace sexp.
	      (if c-recognize-<>-arglists
		  (while (and
			  (progn
			    (c-syntactic-skip-backward "^;$,=<>" lim t)
			    (> (point) lim))
			  (or
			   (when c-overloadable-operators-regexp
			     (when (setq placeholder (c-after-special-operator-id lim))
			       (goto-char placeholder)
			       t))
			   (cond
			    ((eq (char-before) ?>)
			     (or (c-backward-<>-arglist nil lim)
				 (backward-char))
			     t)
			    ((eq (char-before) ?<)
			     (backward-char)
			     (if (save-excursion
				   (c-forward-<>-arglist nil))
				 (progn (forward-char)
					nil)
			       t))
			    (t nil)))))
		;; NB: No c-after-special-operator-id stuff in this
		;; clause - we assume only C++ needs it.
		(c-syntactic-skip-backward "^;$,=" lim t))
	      (memq (char-before) '(?, ?= ?<)))
	    (cond

	     ;; CASE 5D.3: perhaps a template list continuation?
	     ((and (c-major-mode-is 'c++-mode)
		   (save-excursion
		     (save-restriction
		       (c-with-syntax-table c++-template-syntax-table
			 (goto-char indent-point)
			 (setq placeholder (c-up-list-backward))
			 (and placeholder
			      (eq (char-after placeholder) ?<))))))
	      (c-with-syntax-table c++-template-syntax-table
		(goto-char placeholder)
		(c-beginning-of-statement-1 lim t)
		(if (save-excursion
		      (c-backward-syntactic-ws lim)
		      (eq (char-before) ?<))
		    ;; In a nested template arglist.
		    (progn
		      (goto-char placeholder)
		      (c-syntactic-skip-backward "^,;" lim t)
		      (c-forward-syntactic-ws))
		  (back-to-indentation)))
	      ;; FIXME: Should use c-add-stmt-syntax, but it's not yet
	      ;; template aware.
	      (c-add-syntax 'template-args-cont (point) placeholder))

	     ;; CASE 5D.4: perhaps a multiple inheritance line?
	     ((and (c-major-mode-is 'c++-mode)
		   (save-excursion
		     (c-beginning-of-statement-1 lim)
		     (setq placeholder (point))
		     (if (looking-at "static\\>[^_]")
			 (c-forward-token-2 1 nil indent-point))
		     (and (looking-at c-class-key)
			  (zerop (c-forward-token-2 2 nil indent-point))
			  (if (eq (char-after) ?<)
			      (c-with-syntax-table c++-template-syntax-table
				(zerop (c-forward-token-2 1 t indent-point)))
			    t)
			  (eq (char-after) ?:))))
	      (goto-char placeholder)
	      (c-add-syntax 'inher-cont (c-point 'boi)))

	     ;; CASE 5D.5: Continuation of the "expression part" of a
	     ;; top level construct.  Or, perhaps, an unrecognized construct.
	     (t
	      (while (and (setq placeholder (point))
			  (eq (car (c-beginning-of-decl-1 containing-sexp))
			      'same)
			  (save-excursion
			    (c-backward-syntactic-ws)
			    (eq (char-before) ?}))
			  (< (point) placeholder)))
	      (c-add-stmt-syntax
	       (cond
		((eq (point) placeholder) 'statement) ; unrecognized construct
		   ;; A preceding comma at the top level means that a
		   ;; new variable declaration starts here.  Use
		   ;; topmost-intro-cont for it, for consistency with
		   ;; the first variable declaration.  C.f. case 5N.
		((eq char-before-ip ?,) 'topmost-intro-cont)
		(t 'statement-cont))
	       nil nil containing-sexp paren-state))
	     ))

	   ;; CASE 5F: Close of a non-class declaration level block.
	   ((and (eq char-after-ip ?})
		 (c-keyword-member containing-decl-kwd
				   'c-other-block-decl-kwds))
	    ;; This is inconsistent: Should use `containing-decl-open'
	    ;; here if it's at boi, like in case 5J.
	    (goto-char containing-decl-start)
	    (c-add-stmt-syntax
	      (if (string-equal (symbol-name containing-decl-kwd) "extern")
		  ;; Special case for compatibility with the
		  ;; extern-lang syntactic symbols.
		  'extern-lang-close
		(intern (concat (symbol-name containing-decl-kwd)
				"-close")))
	      nil t
	      (c-most-enclosing-brace paren-state (point))
	      paren-state))

	   ;; CASE 5G: we are looking at the brace which closes the
	   ;; enclosing nested class decl
	   ((and containing-sexp
		 (eq char-after-ip ?})
		 (eq containing-decl-open containing-sexp))
	    (c-add-class-syntax 'class-close
				containing-decl-open
				containing-decl-start
				containing-decl-kwd
				paren-state))

	   ;; CASE 5H: we could be looking at subsequent knr-argdecls
	   ((and c-recognize-knr-p
		 (not containing-sexp)	; can't be knr inside braces.
		 (not (eq char-before-ip ?}))
		 (save-excursion
		   (setq placeholder (cdr (c-beginning-of-decl-1 lim)))
		   (and placeholder
			;; Do an extra check to avoid tripping up on
			;; statements that occur in invalid contexts
			;; (e.g. in macro bodies where we don't really
			;; know the context of what we're looking at).
			(not (and c-opt-block-stmt-key
				  (looking-at c-opt-block-stmt-key)))))
		 (< placeholder indent-point))
	    (goto-char placeholder)
	    (c-add-syntax 'knr-argdecl (point)))

	   ;; CASE 5I: ObjC method definition.
	   ((and c-opt-method-key
		 (looking-at c-opt-method-key))
	    (c-beginning-of-statement-1 nil t)
	    (if (= (point) indent-point)
		;; Handle the case when it's the first (non-comment)
		;; thing in the buffer.  Can't look for a 'same return
		;; value from cbos1 since ObjC directives currently
		;; aren't recognized fully, so that we get 'same
		;; instead of 'previous if it moved over a preceding
		;; directive.
		(goto-char (point-min)))
	    (c-add-syntax 'objc-method-intro (c-point 'boi)))

           ;; CASE 5P: AWK pattern or function or continuation
           ;; thereof.
           ((c-major-mode-is 'awk-mode)
            (setq placeholder (point))
            (c-add-stmt-syntax
             (if (and (eq (c-beginning-of-statement-1) 'same)
                      (/= (point) placeholder))
                 'topmost-intro-cont
               'topmost-intro)
             nil nil
             containing-sexp paren-state))

	   ;; CASE 5N: At a variable declaration that follows a class
	   ;; definition or some other block declaration that doesn't
	   ;; end at the closing '}'.  C.f. case 5D.5.
	   ((progn
	      (c-backward-syntactic-ws lim)
	      (and (eq (char-before) ?})
		   (save-excursion
		     (let ((start (point)))
		       (if (and c-state-cache
				(consp (car c-state-cache))
				(eq (cdar c-state-cache) (point)))
			   ;; Speed up the backward search a bit.
			   (goto-char (caar c-state-cache)))
		       (c-beginning-of-decl-1 containing-sexp)
		       (setq placeholder (point))
		       (if (= start (point))
			   ;; The '}' is unbalanced.
			   nil
			 (c-end-of-decl-1)
			 (>= (point) indent-point))))))
	    (goto-char placeholder)
	    (c-add-stmt-syntax 'topmost-intro-cont nil nil
			       containing-sexp paren-state))

	   ;; NOTE: The point is at the end of the previous token here.

	   ;; CASE 5J: we are at the topmost level, make
	   ;; sure we skip back past any access specifiers
	   ((and
	     ;; A macro continuation line is never at top level.
	     (not (and macro-start
		       (> indent-point macro-start)))
	     (save-excursion
	       (setq placeholder (point))
	       (or (memq char-before-ip '(?\; ?$ ?{ ?} nil))
		   (c-at-vsemi-p before-ws-ip)
		   (when (and (eq char-before-ip ?:)
			      (eq (c-beginning-of-statement-1 lim)
				  'label))
		     (c-backward-syntactic-ws lim)
		     (setq placeholder (point)))
		   (and (c-major-mode-is 'objc-mode)
			(catch 'not-in-directive
			  (c-beginning-of-statement-1 lim)
			  (setq placeholder (point))
			  (while (and (c-forward-objc-directive)
				      (< (point) indent-point))
			    (c-forward-syntactic-ws)
			    (if (>= (point) indent-point)
				(throw 'not-in-directive t))
			    (setq placeholder (point)))
			  nil)))))
	    ;; For historic reasons we anchor at bol of the last
	    ;; line of the previous declaration.  That's clearly
	    ;; highly bogus and useless, and it makes our lives hard
	    ;; to remain compatible.  :P
	    (goto-char placeholder)
	    (c-add-syntax 'topmost-intro (c-point 'bol))
	    (if containing-decl-open
		(if (c-keyword-member containing-decl-kwd
				      'c-other-block-decl-kwds)
		    (progn
		      (goto-char (c-brace-anchor-point containing-decl-open))
		      (c-add-stmt-syntax
		       (if (string-equal (symbol-name containing-decl-kwd)
					 "extern")
			   ;; Special case for compatibility with the
			   ;; extern-lang syntactic symbols.
			   'inextern-lang
			 (intern (concat "in"
					 (symbol-name containing-decl-kwd))))
		       nil t
		       (c-most-enclosing-brace paren-state (point))
		       paren-state))
		  (c-add-class-syntax 'inclass
				      containing-decl-open
				      containing-decl-start
				      containing-decl-kwd
				      paren-state)))
	    (when (and c-syntactic-indentation-in-macros
		       macro-start
		       (/= macro-start (c-point 'boi indent-point)))
	      (c-add-syntax 'cpp-define-intro)
	      (setq macro-start nil)))

	   ;; CASE 5K: we are at an ObjC method definition
	   ;; continuation line.
	   ((and c-opt-method-key
		 (save-excursion
		   (c-beginning-of-statement-1 lim)
		   (beginning-of-line)
		   (when (looking-at c-opt-method-key)
		     (setq placeholder (point)))))
	    (c-add-syntax 'objc-method-args-cont placeholder))

	   ;; CASE 5L: we are at the first argument of a template
	   ;; arglist that begins on the previous line.
	   ((and c-recognize-<>-arglists
		 (eq (char-before) ?<)
		 (setq placeholder (1- (point)))
		 (not (and c-overloadable-operators-regexp
			   (c-after-special-operator-id lim))))
	    (c-beginning-of-statement-1 (c-safe-position (point) paren-state))
	    (c-add-syntax 'template-args-cont (c-point 'boi) placeholder))

	   ;; CASE 5Q: we are at a statement within a macro.
	   (macro-start
	    (c-beginning-of-statement-1 containing-sexp)
	    (c-add-stmt-syntax 'statement nil t containing-sexp paren-state))

	   ;; CASE 5M: we are at a topmost continuation line
	   (t
	    (c-beginning-of-statement-1 (c-safe-position (point) paren-state))
	    (when (c-major-mode-is 'objc-mode)
	      (setq placeholder (point))
	      (while (and (c-forward-objc-directive)
			  (< (point) indent-point))
		(c-forward-syntactic-ws)
		(setq placeholder (point)))
	      (goto-char placeholder))
	    (c-add-syntax 'topmost-intro-cont (c-point 'boi)))
	   ))

	 ;; (CASE 6 has been removed.)

	 ;; CASE 19: line is an expression, not a statement, and is directly
	 ;; contained by a template delimiter.  Most likely, we are in a
	 ;; template arglist within a statement.  This case is based on CASE
	 ;; 7.  At some point in the future, we may wish to create more
	 ;; syntactic symbols such as `template-intro',
	 ;; `template-cont-nonempty', etc., and distinguish between them as we
	 ;; do for `arglist-intro' etc. (2009-12-07).
	 ((and c-recognize-<>-arglists
	       (setq containing-< (c-up-list-backward indent-point containing-sexp))
	       (eq (char-after containing-<) ?\<))
	  (setq placeholder (c-point 'boi containing-<))
	  (goto-char containing-sexp)	; Most nested Lbrace/Lparen (but not
					; '<') before indent-point.
	  (if (>= (point) placeholder)
	      (progn
		(forward-char)
		(skip-chars-forward " \t"))
	    (goto-char placeholder))
	  (c-add-stmt-syntax 'template-args-cont (list containing-<) t
			     (c-most-enclosing-brace c-state-cache (point))
			     paren-state))
			     

	 ;; CASE 7: line is an expression, not a statement.  Most
	 ;; likely we are either in a function prototype or a function
	 ;; call argument list, or a template argument list.
	 ((not (or (and c-special-brace-lists
			(save-excursion
			  (goto-char containing-sexp)
			  (c-looking-at-special-brace-list)))
		   (eq (char-after containing-sexp) ?{)
		   (eq (char-after containing-sexp) ?<)))
	  (cond

	   ;; CASE 7A: we are looking at the arglist closing paren.
	   ;; C.f. case 7F.
	   ((memq char-after-ip '(?\) ?\]))
	    (goto-char containing-sexp)
	    (setq placeholder (c-point 'boi))
	    (if (and (c-safe (backward-up-list 1) t)
		     (>= (point) placeholder))
		(progn
		  (forward-char)
		  (skip-chars-forward " \t"))
	      (goto-char placeholder))
	    (c-add-stmt-syntax 'arglist-close (list containing-sexp) t
			       (c-most-enclosing-brace paren-state (point))
			       paren-state))

	   ;; CASE 7B: Looking at the opening brace of an
	   ;; in-expression block or brace list.  C.f. cases 4, 16A
	   ;; and 17E.
	   ((and (eq char-after-ip ?{)
		 (progn
		   (setq placeholder (c-inside-bracelist-p (point)
							   paren-state nil))
		   (if placeholder
		       (setq tmpsymbol '(brace-list-open . inexpr-class))
		     (setq tmpsymbol '(block-open . inexpr-statement)
			   placeholder
			   (cdr-safe (c-looking-at-inexpr-block
				      (c-safe-position containing-sexp
						       paren-state)
				      containing-sexp)))
		     ;; placeholder is nil if it's a block directly in
		     ;; a function arglist.  That makes us skip out of
		     ;; this case.
		     )))
	    (goto-char placeholder)
	    (back-to-indentation)
	    (c-add-stmt-syntax (car tmpsymbol) nil t
			       (c-most-enclosing-brace paren-state (point))
			       paren-state)
	    (if (/= (point) placeholder)
		(c-add-syntax (cdr tmpsymbol))))

	   ;; CASE 7C: we are looking at the first argument in an empty
	   ;; argument list. Use arglist-close if we're actually
	   ;; looking at a close paren or bracket.
	   ((memq char-before-ip '(?\( ?\[))
	    (goto-char containing-sexp)
	    (setq placeholder (c-point 'boi))
	    (if (and (c-safe (backward-up-list 1) t)
		     (>= (point) placeholder))
		(progn
		  (forward-char)
		  (skip-chars-forward " \t"))
	      (goto-char placeholder))
	    (c-add-stmt-syntax 'arglist-intro (list containing-sexp) t
			       (c-most-enclosing-brace paren-state (point))
			       paren-state))

	   ;; CASE 7D: we are inside a conditional test clause. treat
	   ;; these things as statements
	   ((progn
	      (goto-char containing-sexp)
	      (and (c-safe (c-forward-sexp -1) t)
		   (looking-at "\\<for\\>[^_]")))
	    (goto-char (1+ containing-sexp))
	    (c-forward-syntactic-ws indent-point)
	    (if (eq char-before-ip ?\;)
		(c-add-syntax 'statement (point))
	      (c-add-syntax 'statement-cont (point))
	      ))

	   ;; CASE 7E: maybe a continued ObjC method call. This is the
	   ;; case when we are inside a [] bracketed exp, and what
	   ;; precede the opening bracket is not an identifier.
	   ((and c-opt-method-key
		 (eq (char-after containing-sexp) ?\[)
		 (progn
		   (goto-char (1- containing-sexp))
		   (c-backward-syntactic-ws (c-point 'bod))
		   (if (not (looking-at c-symbol-key))
		       (c-add-syntax 'objc-method-call-cont containing-sexp))
		   )))

	   ;; CASE 7F: we are looking at an arglist continuation line,
	   ;; but the preceding argument is on the same line as the
	   ;; opening paren.  This case includes multi-line
	   ;; mathematical paren groupings, but we could be on a
	   ;; for-list continuation line.  C.f. case 7A.
	   ((progn
	      (goto-char (1+ containing-sexp))
	      (< (save-excursion
		   (c-forward-syntactic-ws)
		   (point))
		 (c-point 'bonl)))
	    (goto-char containing-sexp)	; paren opening the arglist
	    (setq placeholder (c-point 'boi))
	    (if (and (c-safe (backward-up-list 1) t)
		     (>= (point) placeholder))
		(progn
		  (forward-char)
		  (skip-chars-forward " \t"))
	      (goto-char placeholder))
	    (c-add-stmt-syntax 'arglist-cont-nonempty (list containing-sexp) t
			       (c-most-enclosing-brace c-state-cache (point))
			       paren-state))

	   ;; CASE 7G: we are looking at just a normal arglist
	   ;; continuation line
	   (t (c-forward-syntactic-ws indent-point)
	      (c-add-syntax 'arglist-cont (c-point 'boi)))
	   ))

	 ;; CASE 8: func-local multi-inheritance line
	 ((and (c-major-mode-is 'c++-mode)
	       (save-excursion
		 (goto-char indent-point)
		 (skip-chars-forward " \t")
		 (looking-at c-opt-postfix-decl-spec-key)))
	  (goto-char indent-point)
	  (skip-chars-forward " \t")
	  (cond

	   ;; CASE 8A: non-hanging colon on an inher intro
	   ((eq char-after-ip ?:)
	    (c-backward-syntactic-ws lim)
	    (c-add-syntax 'inher-intro (c-point 'boi)))

	   ;; CASE 8B: hanging colon on an inher intro
	   ((eq char-before-ip ?:)
	    (c-add-syntax 'inher-intro (c-point 'boi)))

	   ;; CASE 8C: a continued inheritance line
	   (t
	    (c-beginning-of-inheritance-list lim)
	    (c-add-syntax 'inher-cont (point))
	    )))

	 ;; CASE 9: we are inside a brace-list
	 ((and (not (c-major-mode-is 'awk-mode))  ; Maybe this isn't needed (ACM, 2002/3/29)
               (setq special-brace-list
                     (or (and c-special-brace-lists ;;;; ALWAYS NIL FOR AWK!!
                              (save-excursion
                                (goto-char containing-sexp)
                                (c-looking-at-special-brace-list)))
                         (c-inside-bracelist-p containing-sexp paren-state t))))
	  (cond

	   ;; CASE 9A: In the middle of a special brace list opener.
	   ((and (consp special-brace-list)
		 (save-excursion
		   (goto-char containing-sexp)
		   (eq (char-after) ?\())
		 (eq char-after-ip (car (cdr special-brace-list))))
	    (goto-char (car (car special-brace-list)))
	    (skip-chars-backward " \t")
	    (if (and (bolp)
		     (assoc 'statement-cont
			    (setq placeholder (c-guess-basic-syntax))))
		(setq c-syntactic-context placeholder)
	      (c-beginning-of-statement-1
	       (c-safe-position (1- containing-sexp) paren-state))
	      (c-forward-token-2 0)
	      (while (looking-at c-specifier-key)
		(goto-char (match-end 1))
		(c-forward-syntactic-ws))
	      (c-add-syntax 'brace-list-open (c-point 'boi))))

	   ;; CASE 9B: brace-list-close brace
	   ((if (consp special-brace-list)
		;; Check special brace list closer.
		(progn
		  (goto-char (car (car special-brace-list)))
		  (save-excursion
		    (goto-char indent-point)
		    (back-to-indentation)
		    (or
		     ;; We were between the special close char and the `)'.
		     (and (eq (char-after) ?\))
			  (eq (1+ (point)) (cdr (car special-brace-list))))
		     ;; We were before the special close char.
		     (and (eq (char-after) (cdr (cdr special-brace-list)))
			  (zerop (c-forward-token-2))
			  (eq (1+ (point)) (cdr (car special-brace-list)))))))
	      ;; Normal brace list check.
	      (and (eq char-after-ip ?})
		   (c-safe (goto-char (c-up-list-backward (point))) t)
		   (= (point) containing-sexp)))
	    (if (eq (point) (c-point 'boi))
		(c-add-syntax 'brace-list-close (point))
	      (setq lim (c-most-enclosing-brace c-state-cache (point)))
	      (c-beginning-of-statement-1 lim)
	      (c-add-stmt-syntax 'brace-list-close nil t lim paren-state)))

	   (t
	    ;; Prepare for the rest of the cases below by going to the
	    ;; token following the opening brace
	    (if (consp special-brace-list)
		(progn
		  (goto-char (car (car special-brace-list)))
		  (c-forward-token-2 1 nil indent-point))
	      (goto-char containing-sexp))
	    (forward-char)
	    (let ((start (point)))
	      (c-forward-syntactic-ws indent-point)
	      (goto-char (max start (c-point 'bol))))
	    (c-skip-ws-forward indent-point)
	    (cond

	     ;; CASE 9C: we're looking at the first line in a brace-list
	     ((= (point) indent-point)
	      (if (consp special-brace-list)
		  (goto-char (car (car special-brace-list)))
		(goto-char containing-sexp))
	      (if (eq (point) (c-point 'boi))
		  (c-add-syntax 'brace-list-intro (point))
		(setq lim (c-most-enclosing-brace c-state-cache (point)))
		(c-beginning-of-statement-1 lim)
		(c-add-stmt-syntax 'brace-list-intro nil t lim paren-state)))

	     ;; CASE 9D: this is just a later brace-list-entry or
	     ;; brace-entry-open
	     (t (if (or (eq char-after-ip ?{)
			(and c-special-brace-lists
			     (save-excursion
			       (goto-char indent-point)
			       (c-forward-syntactic-ws (c-point 'eol))
			       (c-looking-at-special-brace-list (point)))))
		    (c-add-syntax 'brace-entry-open (point))
		  (c-add-syntax 'brace-list-entry (point))
		  ))
	     ))))

	 ;; CASE 10: A continued statement or top level construct.
	 ((and (not (memq char-before-ip '(?\; ?:)))
	       (not (c-at-vsemi-p before-ws-ip))
	       (or (not (eq char-before-ip ?}))
		   (c-looking-at-inexpr-block-backward c-state-cache))
	       (> (point)
		  (save-excursion
		    (c-beginning-of-statement-1 containing-sexp)
		    (setq placeholder (point))))
	       (/= placeholder containing-sexp))
	  ;; This is shared with case 18.
	  (c-guess-continued-construct indent-point
				       char-after-ip
				       placeholder
				       containing-sexp
				       paren-state))

	 ;; CASE 16: block close brace, possibly closing the defun or
	 ;; the class
	 ((eq char-after-ip ?})
	  ;; From here on we have the next containing sexp in lim.
	  (setq lim (c-most-enclosing-brace paren-state))
	  (goto-char containing-sexp)
	    (cond

	     ;; CASE 16E: Closing a statement block?  This catches
	     ;; cases where it's preceded by a statement keyword,
	     ;; which works even when used in an "invalid" context,
	     ;; e.g. a macro argument.
	     ((c-after-conditional)
	      (c-backward-to-block-anchor lim)
	      (c-add-stmt-syntax 'block-close nil t lim paren-state))

	     ;; CASE 16A: closing a lambda defun or an in-expression
	     ;; block?  C.f. cases 4, 7B and 17E.
	     ((setq placeholder (c-looking-at-inexpr-block
				 (c-safe-position containing-sexp paren-state)
				 nil))
	      (setq tmpsymbol (if (eq (car placeholder) 'inlambda)
				  'inline-close
				'block-close))
	      (goto-char containing-sexp)
	      (back-to-indentation)
	      (if (= containing-sexp (point))
		  (c-add-syntax tmpsymbol (point))
		(goto-char (cdr placeholder))
		(back-to-indentation)
		(c-add-stmt-syntax tmpsymbol nil t
				   (c-most-enclosing-brace paren-state (point))
				   paren-state)
		(if (/= (point) (cdr placeholder))
		    (c-add-syntax (car placeholder)))))

	     ;; CASE 16B: does this close an inline or a function in
	     ;; a non-class declaration level block?
	     ((save-excursion
		(and lim
		     (progn
		       (goto-char lim)
		       (c-looking-at-decl-block
			(c-most-enclosing-brace paren-state lim)
			nil))
		     (setq placeholder (point))))
	      (c-backward-to-decl-anchor lim)
	      (back-to-indentation)
	      (if (save-excursion
		    (goto-char placeholder)
		    (looking-at c-other-decl-block-key))
		  (c-add-syntax 'defun-close (point))
		(c-add-syntax 'inline-close (point))))

	     ;; CASE 16F: Can be a defun-close of a function declared
	     ;; in a statement block, e.g. in Pike or when using gcc
	     ;; extensions, but watch out for macros followed by
	     ;; blocks.  Let it through to be handled below.
	     ;; C.f. cases B.3 and 17G.
	     ((save-excursion
		(and (not (c-at-statement-start-p))
		     (eq (c-beginning-of-statement-1 lim nil nil t) 'same)
		     (setq placeholder (point))
		     (let ((c-recognize-typeless-decls nil))
		       ;; Turn off recognition of constructs that
		       ;; lacks a type in this case, since that's more
		       ;; likely to be a macro followed by a block.
		       (c-forward-decl-or-cast-1 (c-point 'bosws) nil nil))))
	      (back-to-indentation)
	      (if (/= (point) containing-sexp)
		  (goto-char placeholder))
	      (c-add-stmt-syntax 'defun-close nil t lim paren-state))

	     ;; CASE 16C: If there is an enclosing brace then this is
	     ;; a block close since defun closes inside declaration
	     ;; level blocks have been handled above.
	     (lim
	      ;; If the block is preceded by a case/switch label on
	      ;; the same line, we anchor at the first preceding label
	      ;; at boi.  The default handling in c-add-stmt-syntax
	      ;; really fixes it better, but we do like this to keep
	      ;; the indentation compatible with version 5.28 and
	      ;; earlier.  C.f. case 17H.
	      (while (and (/= (setq placeholder (point)) (c-point 'boi))
			  (eq (c-beginning-of-statement-1 lim) 'label)))
	      (goto-char placeholder)
	      (if (looking-at c-label-kwds-regexp)
		  (c-add-syntax 'block-close (point))
		(goto-char containing-sexp)
		;; c-backward-to-block-anchor not necessary here; those
		;; situations are handled in case 16E above.
		(c-add-stmt-syntax 'block-close nil t lim paren-state)))

	     ;; CASE 16D: Only top level defun close left.
	     (t
	      (goto-char containing-sexp)
	      (c-backward-to-decl-anchor lim)
	      (c-add-stmt-syntax 'defun-close nil nil
				 (c-most-enclosing-brace paren-state)
				 paren-state))
	     ))

	 ;; CASE 17: Statement or defun catchall.
	 (t
	  (goto-char indent-point)
	  ;; Back up statements until we find one that starts at boi.
	  (while (let* ((prev-point (point))
			(last-step-type (c-beginning-of-statement-1
					 containing-sexp)))
		   (if (= (point) prev-point)
		       (progn
			 (setq step-type (or step-type last-step-type))
			 nil)
		     (setq step-type last-step-type)
		     (/= (point) (c-point 'boi)))))
	  (cond

	   ;; CASE 17B: continued statement
	   ((and (eq step-type 'same)
		 (/= (point) indent-point))
	    (c-add-stmt-syntax 'statement-cont nil nil
			       containing-sexp paren-state))

	   ;; CASE 17A: After a case/default label?
	   ((progn
	      (while (and (eq step-type 'label)
			  (not (looking-at c-label-kwds-regexp)))
		(setq step-type
		      (c-beginning-of-statement-1 containing-sexp)))
	      (eq step-type 'label))
	    (c-add-stmt-syntax (if (eq char-after-ip ?{)
				   'statement-case-open
				 'statement-case-intro)
			       nil t containing-sexp paren-state))

	   ;; CASE 17D: any old statement
	   ((progn
	      (while (eq step-type 'label)
		(setq step-type
		      (c-beginning-of-statement-1 containing-sexp)))
	      (eq step-type 'previous))
	    (c-add-stmt-syntax 'statement nil t
			       containing-sexp paren-state)
	    (if (eq char-after-ip ?{)
		(c-add-syntax 'block-open)))

	   ;; CASE 17I: Inside a substatement block.
	   ((progn
	      ;; The following tests are all based on containing-sexp.
	      (goto-char containing-sexp)
	      ;; From here on we have the next containing sexp in lim.
	      (setq lim (c-most-enclosing-brace paren-state containing-sexp))
	      (c-after-conditional))
	    (c-backward-to-block-anchor lim)
	    (c-add-stmt-syntax 'statement-block-intro nil t
			       lim paren-state)
	    (if (eq char-after-ip ?{)
		(c-add-syntax 'block-open)))

	   ;; CASE 17E: first statement in an in-expression block.
	   ;; C.f. cases 4, 7B and 16A.
	   ((setq placeholder (c-looking-at-inexpr-block
			       (c-safe-position containing-sexp paren-state)
			       nil))
	    (setq tmpsymbol (if (eq (car placeholder) 'inlambda)
				'defun-block-intro
			      'statement-block-intro))
	    (back-to-indentation)
	    (if (= containing-sexp (point))
		(c-add-syntax tmpsymbol (point))
	      (goto-char (cdr placeholder))
	      (back-to-indentation)
	      (c-add-stmt-syntax tmpsymbol nil t
				 (c-most-enclosing-brace c-state-cache (point))
				 paren-state)
	      (if (/= (point) (cdr placeholder))
		  (c-add-syntax (car placeholder))))
	    (if (eq char-after-ip ?{)
		(c-add-syntax 'block-open)))

	   ;; CASE 17F: first statement in an inline, or first
	   ;; statement in a top-level defun. we can tell this is it
	   ;; if there are no enclosing braces that haven't been
	   ;; narrowed out by a class (i.e. don't use bod here).
	   ((save-excursion
	      (or (not (setq placeholder (c-most-enclosing-brace
					  paren-state)))
		  (and (progn
			 (goto-char placeholder)
			 (eq (char-after) ?{))
		       (c-looking-at-decl-block (c-most-enclosing-brace
						 paren-state (point))
						nil))))
	    (c-backward-to-decl-anchor lim)
	    (back-to-indentation)
	    (c-add-syntax 'defun-block-intro (point)))

	   ;; CASE 17G: First statement in a function declared inside
	   ;; a normal block.  This can occur in Pike and with
	   ;; e.g. the gcc extensions, but watch out for macros
	   ;; followed by blocks.  C.f. cases B.3 and 16F.
	   ((save-excursion
	      (and (not (c-at-statement-start-p))
		   (eq (c-beginning-of-statement-1 lim nil nil t) 'same)
		   (setq placeholder (point))
		   (let ((c-recognize-typeless-decls nil))
		     ;; Turn off recognition of constructs that lacks
		     ;; a type in this case, since that's more likely
		     ;; to be a macro followed by a block.
		     (c-forward-decl-or-cast-1 (c-point 'bosws) nil nil))))
	    (back-to-indentation)
	    (if (/= (point) containing-sexp)
		(goto-char placeholder))
	    (c-add-stmt-syntax 'defun-block-intro nil t
			       lim paren-state))

	   ;; CASE 17H: First statement in a block.
	   (t
	    ;; If the block is preceded by a case/switch label on the
	    ;; same line, we anchor at the first preceding label at
	    ;; boi.  The default handling in c-add-stmt-syntax is
	    ;; really fixes it better, but we do like this to keep the
	    ;; indentation compatible with version 5.28 and earlier.
	    ;; C.f. case 16C.
	    (while (and (/= (setq placeholder (point)) (c-point 'boi))
			(eq (c-beginning-of-statement-1 lim) 'label)))
	    (goto-char placeholder)
	    (if (looking-at c-label-kwds-regexp)
		(c-add-syntax 'statement-block-intro (point))
	      (goto-char containing-sexp)
	      ;; c-backward-to-block-anchor not necessary here; those
	      ;; situations are handled in case 17I above.
	      (c-add-stmt-syntax 'statement-block-intro nil t
				 lim paren-state))
	    (if (eq char-after-ip ?{)
		(c-add-syntax 'block-open)))
	   ))
	 )

	;; now we need to look at any modifiers
	(goto-char indent-point)
	(skip-chars-forward " \t")

	;; are we looking at a comment only line?
	(when (and (looking-at c-comment-start-regexp)
		   (/= (c-forward-token-2 0 nil (c-point 'eol)) 0))
	  (c-append-syntax 'comment-intro))

	;; we might want to give additional offset to friends (in C++).
	(when (and c-opt-friend-key
		   (looking-at c-opt-friend-key))
	  (c-append-syntax 'friend))

	;; Set syntactic-relpos.
	(let ((p c-syntactic-context))
	  (while (and p
		      (if (integerp (c-langelem-pos (car p)))
			  (progn
			    (setq syntactic-relpos (c-langelem-pos (car p)))
			    nil)
			t))
	    (setq p (cdr p))))

	;; Start of or a continuation of a preprocessor directive?
	(if (and macro-start
		 (eq macro-start (c-point 'boi))
		 (not (and (c-major-mode-is 'pike-mode)
			   (eq (char-after (1+ macro-start)) ?\"))))
	    (c-append-syntax 'cpp-macro)
	  (when (and c-syntactic-indentation-in-macros macro-start)
	    (if in-macro-expr
		(when (or
		       (< syntactic-relpos macro-start)
		       (not (or
			     (assq 'arglist-intro c-syntactic-context)
			     (assq 'arglist-cont c-syntactic-context)
			     (assq 'arglist-cont-nonempty c-syntactic-context)
			     (assq 'arglist-close c-syntactic-context))))
		  ;; If inside a cpp expression, i.e. anywhere in a
		  ;; cpp directive except a #define body, we only let
		  ;; through the syntactic analysis that is internal
		  ;; in the expression.  That means the arglist
		  ;; elements, if they are anchored inside the cpp
		  ;; expression.
		  (setq c-syntactic-context nil)
		  (c-add-syntax 'cpp-macro-cont macro-start))
	      (when (and (eq macro-start syntactic-relpos)
			 (not (assq 'cpp-define-intro c-syntactic-context))
			 (save-excursion
			   (goto-char macro-start)
			   (or (not (c-forward-to-cpp-define-body))
			       (<= (point) (c-point 'boi indent-point)))))
		;; Inside a #define body and the syntactic analysis is
		;; anchored on the start of the #define.  In this case
		;; we add cpp-define-intro to get the extra
		;; indentation of the #define body.
		(c-add-syntax 'cpp-define-intro)))))

	;; return the syntax
	c-syntactic-context)))

;;;; End of `asir-c-guess-basic-syntax'

(provide 'asir-mode)
