+(defun simula-search-backward (regexp &optional bound noerror)
+ "Search backward from point for regular expression REGEXP, ignoring matches
+found inside SIMULA comments, string literals, and BEGIN..END blocks.
+Set point to the end of the occurrence found, and return point.
+An optional second argument BOUND bounds the search, it is a buffer position.
+The match found must not extend after that position. Optional third argument
+NOERROR, if t, means if fail just return nil (no error).
+If not nil and not t, move to limit of search and return nil."
+ (let (begin end context (comb-regexp (concat regexp "\\|\\<end\\>"))
+ match (start-point (point)))
+ (catch 'simula-backward
+ (while (re-search-backward comb-regexp bound 1)
+ ;; We have a match, check SIMULA context at match-beginning
+ ;; to see if we are outside comments etc.
+ ;; Set MATCH to t if we found a true match,
+ ;; set MATCH to 'BLOCK if we found a BEGIN..END block,
+ ;; else set MATCH to nil.
+ (save-match-data
+ (setq context (simula-context))
+ (cond
+ ((eq context nil)
+ (setq match (if (looking-at regexp) t 'BLOCK)))
+;;; A comment-ending semicolon is part of the comment, and shouldn't match.
+;;; ((eq context 0)
+;;; (setq match (if (eq (following-char) ?\;) t nil)))
+ ((eq context 2)
+ (setq match (if (and (looking-at regexp)
+ (looking-at ";\\|\\<end\\>\\|\\<else\\>\\|\\<otherwise\\>\\|\\<when\\>"))
+ t
+ (if (looking-at "\\<end\\>") 'BLOCK nil))))
+ (t (setq match nil))))
+ ;; Exit if true match
+ (if (eq match t) (throw 'simula-backward (point)))
+ (if (eq match 'BLOCK)
+ ;; We found the END of a block
+ (let ((level 0))
+ (while (natnump level)
+ (if (re-search-backward "\\<begin\\>\\|\\<end\\>" bound 1)
+ (let ((context (simula-context)))
+ ;; We found a BEGIN -> decrease level count
+ (cond ((and (eq context nil)
+ (memq (following-char) '(?b ?B)))
+ (setq level (1- level)))
+ ;; END -> increase level count
+ ((and (memq context '(nil 2))
+ (memq (following-char) '(?e ?E)))
+ (setq level (1+ level)))))
+ ;; Block search failed. Action depends on noerror.
+ (if (or (not noerror) (eq noerror t))
+ (goto-char start-point))
+ (if (not noerror)
+ (signal 'search-failed (list regexp)))
+ (throw 'simula-backward nil))))))
+ ;; Search failed. Action depends on noerror.
+ (if (or (not noerror) (eq noerror t))
+ (goto-char start-point))
+ (if noerror
+ nil
+ (signal 'search-failed (list regexp))))))
+
+
+(defun simula-search-forward (regexp &optional bound noerror)
+ "Search forward from point for regular expression REGEXP, ignoring matches
+found inside SIMULA comments, string literals, and BEGIN..END blocks.
+Set point to the end of the occurrence found, and return point.
+An optional second argument BOUND bounds the search, it is a buffer position.
+The match found must not extend after that position. Optional third argument
+NOERROR, if t, means if fail just return nil (no error).
+If not nil and not t, move to limit of search and return nil."
+ (let (begin end context (comb-regexp (concat regexp "\\|\\<begin\\>"))
+ match (start-point (point)))
+ (catch 'simula-forward
+ (while (re-search-forward comb-regexp bound 1)
+ ;; We have a match, check SIMULA context at match-beginning
+ ;; to see if we are outside comments.
+ ;; Set MATCH to t if we found a true match,
+ ;; set MATCH to 'BLOCK if we found a BEGIN..END block,
+ ;; else set MATCH to nil.
+ (save-match-data
+ (save-excursion
+ (goto-char (match-beginning 0))
+ (setq context (simula-context))
+ (cond
+ ((not context)
+ (setq match (if (looking-at regexp) t 'BLOCK)))
+;;; A comment-ending semicolon is part of the comment, and shouldn't match.
+;;; ((eq context 0)
+;;; (setq match (if (eq (following-char) ?\;) t nil)))
+ ((eq context 2)
+ (setq match (if (and (looking-at regexp)
+ (looking-at ";\\|\\<end\\>\\|\\<else\\>\\|\\<otherwise\\>\\|\\<when\\>")) t nil)))
+ (t (setq match nil)))))
+ ;; Exit if true match
+ (if (eq match t) (throw 'simula-forward (point)))
+ (if (eq match 'BLOCK)
+ ;; We found the BEGINning of a block
+ (let ((level 0))
+ (while (natnump level)
+ (if (re-search-forward "\\<begin\\>\\|\\<end\\>" bound 1)
+ (let ((context (simula-context)))
+ ;; We found a BEGIN -> increase level count
+ (cond ((eq context nil) (setq level (1+ level)))
+ ;; END -> decrease level count
+ ((and (eq context 2)
+ ;; Don't match BEGIN inside END comment
+ (memq (preceding-char) '(?d ?D)))
+ (setq level (1- level)))))
+ ;; Block search failed. Action depends on noerror.
+ (if (or (not noerror) (eq noerror t))
+ (goto-char start-point))
+ (if (not noerror)
+ (signal 'search-failed (list regexp)))
+ (throw 'simula-forward nil))))))
+ ;; Search failed. Action depends on noerror.
+ (if (or (not noerror) (eq noerror t))
+ (goto-char start-point))
+ (if noerror
+ nil
+ (signal 'search-failed (list regexp))))))