;;; synopsys-mode.el --- Synopsys dc_shell script editing mode for (X)emacs ;; ;; Keywords: Synopsys ;; Author: Hartley Horwitz (harts@nortel.ca) ;; NORTEL ;; Northern Telecom Ltd. (Semiconductor Division) ;; Ottawa, Canada ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; $Id: synopsys-mode.el,v 1.23 1998/03/26 23:01:53 harts Exp $ ;;; Commentary: ;; An editing mode for Synopsys dc_shell scripts. It knows a lot ;; about Synopsys syntax and tries to indent and format lines in a ;; manner similar to c-code. One of the biggest advantages is the ;; font-lock support. I find that font-lock support has helped us confirm ;; the proper spelling of a lot of commands. Of course, this implies that ;; all the Synopsys commands are supported in this mode - they are not, but ;; the most used commands and command options are supported. ;; ;; You can change the details of the layout style ;; with option variables. Load it and do M-x describe-mode for details. ;; ;; Various levels of fontification are supported. By default, I've set things ;; to maximum fontification (level 3). Fontification levels are modified ;; by setting the `synopsys-font-lock-highlight-level' variable. For example ;; to highlight only comments and strings, add the following to your .emacs: ;; (setq synopsys-font-lock-highlight-level nil) ;; ;; This mode borrowed from the old c-mode. ;; ;; I've written this mode with Synopsys version 97.01 in mind. The old command ;; format is not supported, but Synopsys provides the `update_script' command ;; to assist you in upgrading old scripts. Commands found in the versions ;; newer than 97.01 can be added to font-lock, if a bug report is sent to me. ;; ;; Synopsys has not endorsed or otherwise sanctioned the use of their name ;; and/or command language in this mode. ;;; Usage ;; ;; To use this mode, put this elisp file somewhere in your load path, ;; then add following in your .emacs file: ;; ;; (autoload 'synopsys-mode "synopsys-mode" "Synopsys DC Shell mode" t) ;; ;; Additional things to add to your .emacs file: ;; ;; (setq auto-mode-alist (cons '("\\.dcs$" . synopsys-mode) auto-mode-alist)) ;; (setq auto-mode-alist (cons '("\\.syn[t]*[h]*$" . synopsys-mode) ;; auto-mode-alist)) ;; ;; To over-ride variables for this mode, use the synopsys-mode-hook. For ;; example, putting the following code in your .emacs will remove a lot ;; of the automatic nice features (IMO) in this mode: ;; (add-hook 'synopsys-mode-hook (function (lambda () ;; (setq synopsys-auto-indent nil) ;; (setq synopsys-auto-backslash nil) ;; (setq synopsys-auto-cformat nil)))) ;; ;; ;; The fontification requires a fairly new version of font-lock ;; mode. Emacs version 19.31 (and higher) comes with this version, ;; Xemacs 19.14-19.16 doesn't have it. Update your font-lock if you ;; want Synopsys-mode to properly identify Synopsys comments in all ;; situations. If you don't upgrade, it will get confused when the /* is ;; used as part of a path. I use emacs' font lock package with ;; xemacs-19.16 without problems. If you don't want to upgrade, then ;; fontification of the synopsys 'glob' will not be correct. This isn't ;; so tragic. You be the judge! ;; ;; Synopsys mode help (on C-h m) provides more customization help. If you ;; use font-lock, note that not all Synopsys commands and options are ;; supported. This was done in the interest of speed, although, if enough ;; people complain, I'll update the font-lock keywords to include more ;; commands. ;; Tested on emacs 20.2.1 and Xemacs 19.16. ;;; Bugs/Problems ;; (1) auto-fill mode doesn't work properly with this mode, especially ;; if `synopsys-auto-backslash' is nil. Probably need to write a ;; fill-function, but haven't worked on it. ;; (2) Bug with lazy-lock. For some reason, lazy lock gets called ;; multiple times by something when you enter the following /* blah ;; find(blah/*/. This will hang lazy lock. I've tried debugging this, ;; but even C-g will not stop the infinite loop, so I can't figure out ;; what the problem it. If lazy lock is disabled, or if you don't enter ;; the key sequence given above, you'll be ok. (I still use lazy lock ;; and haven't had a problem, only on my weird test cases.) ;; (3) Don't have support for the font-lock-use-default-maximal-decoration ;; and font-lock-use-default-minimal-decoration variables. You have to ;; specify the level of fontification directly using the ;; `synopsys-font-lock-highlight-level' variable. See the documentation ;; of this variable for details. ;; (4) synopsys-fill-paragraph will not properly indent the last line ;; of a comment if the function is called from the menu or ;; minibuffer. If its called as part of normal code entry, the ;; electric-newline handles the indentation. I haven't fixed this, and ;; I'm not convinced the added overhead is a good idea. Let me know if ;; this really bugs you. ;; (5) need to re-do the synopsys-font-lock-fontify-syntactically-region ;; function since I now know how to do it faster. ;; ;; Bugs can be submitted via the synopsys-submit-bug-report function. ;; ;;;;;;;;;;;;;;;;; ;; $Log: synopsys-mode.el,v $ ;; Revision 1.23 1998/03/26 23:01:53 harts ;; Added the C-cC-c key binding (for comment-region) based on a suggestion ;; from Dmitry. ;; ;; Revision 1.22 1997/12/17 15:02:37 harts ;; Updated the font-lock regexp so that commands with trailing ;; brackets are properly highlighted (Jim Dahlberg's bug). ;; Commands like report_timing(-from zab) are now highlighted. ;; ;; Revision 1.21 1997/12/11 22:32:02 harts ;; Added more comments about the font-lock differences between emacs ;; and Xemacs. Unfortunately, the latest version of Xemacs (19.16) hasn't ;; upgraded its font-lock package to contain the good new features that ;; emacs' font-lock package has. This causes this mode in Xemacs to incorrectly ;; colorize some constructs. If this isn't a problem for you, good. If it ;; bothers you (it bothers me), I make Xemacs point to the emacs font-lock ;; package. ;; ;; Revision 1.20 1997/12/11 21:39:55 harts ;; fixed the menu functions so that Xemacs users get a nicer ;; menu and they don't need to add any fancy stuff to their ;; .emacs file. ;; ;; Revision 1.19 1997/12/11 17:55:28 harts ;; Updated the font-locking to include more 97.01 commands ;; and more -options. Added more bugs that I've found via testing. ;; It seems that Xemacs fontification differs slightly now that I've ;; upgraded! See bug list for details. ;; ;; Revision 1.18 1997/02/28 21:04:39 harts ;; fixed a typo on the first line ;; ;; Revision 1.17 1997/02/11 15:29:45 harts ;; Added a comment to the "defun synopsys-mode" line so that Synopsys ;; mode would be automatically added to the loaddefs.el file. This allows ;; autoloading of the file. Thanks to Brian Silveira for this patch. ;; ;; Revision 1.16 1996/12/13 22:04:34 harts ;; Updated synopsys-fill-paragraph to handle single line comments. ;; If the function is called from within a newline command, and a ;; comment ender hasn't been entered yet, assume a multi-line comment ;; is desired, else assume single-line. Also had to update the ;; way fill-prefix is handled. For comments that have been indented ;; a lot, the indentation will be a mix of tabs and spaces. The ;; comments need to be 'untabified' to allow filling to occur properly. ;; This was added to synopsys-fill-paragraph. ;; ;; Revision 1.15 1996/12/10 22:19:39 harts ;; Updated the synopsys-fill-paragraph function to properly handle ;; single-line comments. These were getting treated as multi-line comments, ;; but this has been fixed. Also, removed all references to electric-semi, ;; this function is no longer part of this mode. ;; ;; Revision 1.15 1996/12/10 22:02:37 harts ;; Updated synopsys-fill-paragraph to fix a bug with single-line ;; comments. Single line comments were not being preserved properly, now ;; they seem to work properly. ;; ;; Revision 1.14 1996/12/10 18:33:18 harts ;; Fixed the comment fill, so that it works correctly for multi-line ;; comments where only 1 line has been entered so far. Also added ;; comment style to the menu. Cleaned up the documentation, removing ;; references to the comment style restrictions. ;; ;; Revision 1.13 1996/12/08 21:46:25 harts ;; Added a new function to submit a bug report - ;; synopsys-submit-bug-report. Also changed the way comment start and ;; comment end: comment start no longer requires a space after it. This ;; requires more careful searching for the start of a comment. Created ;; variables to hold the regexps for comments. These regexps are in ;; addition to the normal comment-start, comment-end, and ;; comment-start-skip. Hard coding of the comment start and end inside the ;; code has been removed completely, replaced by these regexps. ;; Comment formatting has been greatly improved: this mode now supports 5 ;; different styles of comments, set with the synopsys-comment-style ;; variable. This required updates to the synopsys-fill-paragraph function, ;; the calculate-synopsys-indent-within-comment function, and the ;; electric-synopsys-newline function. Minor edits to a few other functions ;; were done. ;; Added the support for various levels of highlighting. This is ;; controlled with the synopsys-font-lock-highlight-level variable. This ;; should satisfy users who have slow machines but still want to use font-lock. ;; ;; ;;;;;;;;;;;;;;;;; ;;; Code: ;; This variable will hold version number of mode (defconst synopsys-mode-version "$$Revision: 1.23 $$" "Version of this synopsys mode.") (defvar synopsys-mode-abbrev-table nil "Abbrev table in use in synopsys mode.") (define-abbrev-table 'synopsys-mode-abbrev-table ()) (defvar synopsys-mode-map (make-sparse-keymap) "Keymap used in synopsys mode.") (define-key synopsys-mode-map "\C-m" 'electric-synopsys-newline) (define-key synopsys-mode-map "\e\C-q" 'indent-synopsys-exp) (define-key synopsys-mode-map "\ea" 'synopsys-beginning-of-statement) (define-key synopsys-mode-map "\ee" 'synopsys-end-of-statement) (define-key synopsys-mode-map "\177" 'backward-delete-char-untabify) (define-key synopsys-mode-map "\t" 'synopsys-indent-command) (define-key synopsys-mode-map "\C-c\C-c" 'comment-region) (define-key synopsys-mode-map "\C-c\C-b" 'synopsys-submit-bug-report) ;;; Help make this compile cleanly (if (fboundp 'eval-when-compile) (eval-when-compile (condition-case nil (progn (require 'easymenu) (require 'reporter)) (error nil)))) ;;; Pull-down menu ;;; (condition-case nil (progn (require 'easymenu) (if (string-match "Xemacs" emacs-version) (defvar synopsys-xemacs-menu '("Synopsys" ["Beginning of statement" synopsys-beginning-of-statement t] ["End of statement" synopsys-end-of-statement t] ["Indent expression" indent-synopsys-exp t] ["Indent line" synopsys-indent-command t] ["Fill Comment" synopsys-fill-paragraph t] ["Add/align/indent Comment" indent-for-comment t] "----" ["Indent region" indent-region t] ["Comment region" comment-region (synopsys-use-region-p)] ["Uncomment region" uncomment-region (synopsys-use-region-p)] ["Backslash region" synopsys-backslash-region (synopsys-use-region-p)] ["Un-backslash region" synopsys-backslash-region (synopsys-use-region-p)] "----" ("Toggle..." ["Auto indent" synopsys-toggle-auto-indent :style radio :selected synopsys-auto-indent ] ["Auto comment format" synopsys-toggle-auto-cformat :style radio :selected synopsys-auto-cformat ] ["Automatically split long lines" synopsys-toggle-auto-backslash :style radio :selected synopsys-auto-backslash ] ["Tab key indents current line" synopsys-toggle-auto-tab :style radio :selected synopsys-tab-always-indent ] ) ("Indentation styles..." ["GNU" (set-synopsys-style "GNU") t] ["K&R" (set-synopsys-style "K&R") t] ["BSD" (set-synopsys-style "BSD") t] ["Whitesmith" (set-synopsys-style "Whitesmith") t] ) ("Comment styles..." ["style 1 (no stars, with space)" (setq synopsys-comment-style 1) :style radio :selected (= synopsys-comment-style 1)] ["style 2 (no stars, with space)" (setq synopsys-comment-style 2) :style radio :selected (= synopsys-comment-style 2)] ["style 3 (1 star)" (setq synopsys-comment-style 3) :style radio :selected (= synopsys-comment-style 3)] ["style 4 (2 stars)" (setq synopsys-comment-style 4) :style radio :selected (= synopsys-comment-style 4)] ["style 5 (no stars, no space)" (setq synopsys-comment-style 5) :style radio :selected (= synopsys-comment-style 5)] ) ) "Synopsys Menu for Xemacs") (easy-menu-define synopsys-menu synopsys-mode-map "Menu for Synopsys Mode" '("Synopsys" ["Beginning of statement" synopsys-beginning-of-statement t] ["End of statement" synopsys-end-of-statement t] ["Indent expression" indent-synopsys-exp t] ["Indent line" synopsys-indent-command t] ["Fill Comment" synopsys-fill-paragraph t] ["Add/align/indent Comment" indent-for-comment t] "----" ["Indent region" indent-region t] ["Comment region" comment-region (synopsys-use-region-p)] ["Uncomment region" uncomment-region (synopsys-use-region-p)] ["Backslash region" synopsys-backslash-region (synopsys-use-region-p)] ["Un-backslash region" synopsys-backslash-region (synopsys-use-region-p)] "----" ("Toggle..." ; works only in Xemacs, need to re-write this? ; ["Auto indent" synopsys-toggle-auto-indent ; :style radio :selected synopsys-auto-indent ] ; ["Auto comment format" synopsys-toggle-auto-cformat ; :style radio :selected synopsys-auto-cformat ] ; ["Automatically split long lines" synopsys-toggle-auto-backslash ; :style radio :selected synopsys-auto-backslash ] ; ["Tab key indents current line" synopsys-toggle-auto-tab ; :style radio :selected synopsys-tab-always-indent ] ["Auto indent" synopsys-toggle-auto-indent t] ["Auto comment format" synopsys-toggle-auto-cformat t] ["Automatically split long lines" synopsys-toggle-auto-backslash t] ["Tab key indents current line" synopsys-toggle-auto-tab t] ) ("Indentation styles..." ["GNU" (set-synopsys-style "GNU") t] ["K&R" (set-synopsys-style "K&R") t] ["BSD" (set-synopsys-style "BSD") t] ["Whitesmith" (set-synopsys-style "Whitesmith") t] ) ("Comment styles..." ; works only in Xemacs ; ["style 1 (no stars, with space)" (setq synopsys-comment-style 1) ; :style radio :selected (= synopsys-comment-style 1)] ; ["style 2 (no stars, with space)" (setq synopsys-comment-style 2) ; :style radio :selected (= synopsys-comment-style 2)] ; ["style 3 (1 star)" (setq synopsys-comment-style 3) ; :style radio :selected (= synopsys-comment-style 3)] ; ["style 4 (2 stars)" (setq synopsys-comment-style 4) ; :style radio :selected (= synopsys-comment-style 4)] ; ["style 5 (no stars, no space)" (setq synopsys-comment-style 5) ; :style radio :selected (= synopsys-comment-style 5)] ["style 1 (no stars, with space)" (setq synopsys-comment-style 1) t] ["style 2 (no stars, with space)" (setq synopsys-comment-style 2) t] ["style 3 (1 star)" (setq synopsys-comment-style 3) t] ["style 4 (2 stars)" (setq synopsys-comment-style 4) t] ["style 5 (no stars, no space)" (setq synopsys-comment-style 5) t] ) )))) (error nil)) ;;; Syntax Table for Synopsys ;;; (defvar synopsys-mode-syntax-table nil "Syntax table in use in synopsys-mode buffers.") (if synopsys-mode-syntax-table () (setq synopsys-mode-syntax-table (make-syntax-table)) (modify-syntax-entry ?\\ "\\" synopsys-mode-syntax-table) (modify-syntax-entry ?/ ". 14" synopsys-mode-syntax-table) (modify-syntax-entry ?* ". 23" synopsys-mode-syntax-table) (modify-syntax-entry ?+ "." synopsys-mode-syntax-table) (modify-syntax-entry ?- "'" synopsys-mode-syntax-table) (modify-syntax-entry ?. "'" synopsys-mode-syntax-table) (modify-syntax-entry ?, "." synopsys-mode-syntax-table) (modify-syntax-entry ?_ "_" synopsys-mode-syntax-table) (modify-syntax-entry ?= "." synopsys-mode-syntax-table) (modify-syntax-entry ?% "." synopsys-mode-syntax-table) (modify-syntax-entry ?< "." synopsys-mode-syntax-table) (modify-syntax-entry ?> "." synopsys-mode-syntax-table) (modify-syntax-entry ?& "." synopsys-mode-syntax-table) (modify-syntax-entry ?| "." synopsys-mode-syntax-table) (modify-syntax-entry ?\' "\"" synopsys-mode-syntax-table)) (defconst synopsys-indent-level 2 "*Indentation of synopsys statements with respect to containing block.") (defconst synopsys-brace-imaginary-offset 0 "*Imagined indentation of a synopsys open brace that actually follows a statement.") (defconst synopsys-brace-offset 0 "*Extra indentation for braces, compared with other text in same context.") (defconst synopsys-continued-statement-offset 2 "*Extra indent for lines not starting new statements.") (defconst synopsys-continued-brace-offset 0 "*Extra indent for substatements that start with open-braces. This is in addition to `synopsys-continued-statement-offset'.") (defconst synopsys-style-alist '(("GNU" (synopsys-indent-level . 2) (synopsys-brace-offset . 0) (synopsys-continued-brace-offset . 0) (synopsys-continued-statement-offset . 2)) ("K&R" (synopsys-indent-level . 5) (synopsys-brace-offset . 0) (synopsys-continued-brace-offset . -5) (synopsys-continued-statement-offset . 5)) ("BSD" (synopsys-indent-level . 4) (synopsys-brace-offset . 0) (synopsys-continued-brace-offset . -4) (synopsys-continued-statement-offset . 4)) ("Whitesmith" (synopsys-indent-level . 4) (synopsys-brace-offset . 0) (synopsys-continued-brace-offset . 0) (synopsys-continued-statement-offset . 4)))) (defconst synopsys-auto-indent t "*Non-nil means automatically indent lines after a newline is entered. If nil, you must manually indent each line, or call \\[indent-region].") (defconst synopsys-auto-cformat t "*Non-nil means automatically fill a comment after the comment end (and newline) have been entered. Comments can be manually filled using \\[synopsys-fill-paragraph]. Five different comment styles are supported. These are controlled via the `synopsys-comment-style' variable. The 5 different styles are described in the documentation. Comment formatting is performed after every newline in a multi-line comment, and after the final comment ender (and a newline) has been entered. This may be annoying, particularly for comments like headers or other comments that are not just text. In this case, you don't want comment formatting. To disable this feature, set the variable to nil") (defconst synopsys-auto-backslash t "*Non-nil means lines longer than `fill-column' will be automatically split into two or more lines, using the backslash continuation character. For backslashing on demand (or removing them), see the `synopsys-backslash-region' function.") (defconst synopsys-tab-always-indent t "*Non-nil means TAB in synopsys mode should always reindent the current line, regardless of where in the line point is when the TAB command is used.") (defconst synopsys-comment-style 1 "*This variable specifies what type of comment-style should be supported (for indentation and comment formatting). This really only makes a difference for multi-line comments. Comment formatting is done with \\[synopsys-fill-paragraph], or automatically by setting `synopsys-auto-cformat'. Values of synopsys-comment-style are: style 1: style 2: style 3: style 4: style 5: /* /* Blah /* /* /* blah blah. */ * blah ** blah blah blah * blah ** blah blah */ */ */ */") ;; Support for font-lock mode ;; All regexp created using the make-regexp lisp package. ;; (defvar synopsys-font-lock-keywords-1 (list ; "add_module" "alias" "analyze" "balance_buffer" ; "balance_registers" "bc_check_design" "bc_time_design" ; "break" "cd" "chain_operations" "change_link" "change_names" ; "characterize" "check_design" "check_implementations" "check_test" ; "check_timing" "compare_design" "compare_fsm" "compile" "connect_net" ; "context_check" "continue" "copy_design" "create_bus" "create_cell" ; "create_clock" "create_net" "create_port" "create_wire_load" ; "disconnect_net" "dont_chain_operations" "drive_of" "echo" ; "eco_align_design" "eco_analyze_design" "eco_current_design_pair" ; "eco_implement" "eco_recycle" "eco_reset_directives" "elaborate" ; "else" "execute" "exit" "extract" "filter" "get_attribute" ; "get_license" "get_unix_variable" "group" "group_path" "include" ; "insert_jtag" "insert_pads" "insert_scan" "insert_test" "link" ; "list_designs" "list_instances" "list_libs" "load_of" "minimize_fsm" ; "optimize_registers" "quit" "read" "read_lib" "read_timing" ; "reduce_fsm" "remove_attribute" "remove_cell" "remove_clock" ; "remove_constraint" "remove_constraint" "remove_design" ; "remove_design" "remove_input_delay" "remove_input_delay" ; "remove_lib" "remove_license" "remove_net" "remove_output_delay" ; "remove_unconnected_ports" "rename_design" "reoptimize_design" ; "replace_synthetic" "report_annotated_delay" "report_area" ; "report_attribute" "report_cell" "report_clock" "report_constraint" ; "report_design" "report_design_lib" "report_hierarchy" ; "report_internal_loads" "report_lib" "report_multicycles" ; "report_net" "report_port" "report_power" "report_reference" ; "report_resources" "report_schedule" "report_scheduling_constraints" ; "report_test" "report_timing" "report_timing_requirements" ; "reset_design" "reset_path" "schedule" "set_annotated_check" ; "set_annotated_delay" "set_attribute" "set_boundary_optimization" ; "set_clock_skew" "set_clock_transition" "set_cycles" ; "set_disable_timing" "set_dont_touch" "set_dont_touch_network" ; "set_dont_use" "set_drive" "set_driving_cell" "set_eco_align" ; "set_eco_reuse" "set_eco_target" "set_eco_unique" "set_equal" ; "set_false_path" "set_fanout_load" "set_fix_hold" "set_flatten" ; "set_fsm_encoding" "set_fsm_encoding_style" "set_fsm_minimize" ; "set_fsm_order" "set_fsm_state_vector" "set_implementation" ; "set_input_delay" "set_load" "set_logic_one" "set_logic_zero" ; "set_max_area" "set_max_capacitance" "set_max_cycles" "set_max_delay" ; "set_max_dynamic_power" "set_max_fanout" "set_max_leakage_power" ; "set_max_time_borrow" "set_max_transition" "set_multicycle_path" ; "set_operating_conditions" "set_output_delay" "set_register_type" ; "set_scan_style" "set_signal_type" "set_structure" ; "set_test_methodology" "set_unconnected" "set_wire_load" "sh" ; "unalias" "ungroup" "uniquify" "unschedule" "update_lib" "which" ; "write" "write_compare_design_script" "write_constraints" "write_lib" ; "write_parasitics" "write_power" "write_script" "write_timing" (list (concat "^[ \t]*\\(" "a\\(dd_module\\|lias\\|nalyze\\)\\|b\\(alance_\\(buffer\\|registers\\)" "\\|c_\\(check_design\\|time_design\\)\\|reak\\)\\|c\\(d\\|h\\(a\\(" "in_operations\\|nge_\\(link\\|names\\)\\|racterize\\)\\|eck_\\(" "design\\|implementations\\|t\\(est\\|iming\\)\\)\\)\\|o\\(mp\\(are_\\(" "design\\|fsm\\)\\|ile\\)\\|n\\(nect_net\\|t\\(ext_check\\|inue\\)\\)" "\\|py_design\\)\\|reate_\\(bus\\|c\\(ell\\|lock\\)\\|net\\|port\\|" "wire_load\\)\\)\\|d\\(isconnect_net\\|ont_chain_operations\\|" "rive_of\\)\\|e\\(c\\(ho\\|o_\\(a\\(lign_design\\|nalyze_design\\)\\|" "current_design_pair\\|implement\\|re\\(cycle\\|set_directives\\)\\)\\)" "\\|l\\(aborate\\|se\\)\\|x\\(ecute\\|it\\|tract\\)\\)\\|filter\\|g\\(" "et_\\(attribute\\|license\\|unix_variable\\)\\|roup\\(\\|_path\\)\\)" "\\|in\\(clude\\|sert_\\(jtag\\|pads\\|scan\\|test\\)\\)\\|l\\(i\\(" "nk\\|st_\\(designs\\|instances\\|libs\\)\\)\\|oad_of\\)\\|" "minimize_fsm\\|optimize_registers\\|quit\\|re\\(ad\\(\\|_\\(lib\\|" "timing\\)\\)\\|duce_fsm\\|move_\\(attribute\\|c\\(ell\\|lock\\|" "onstraint\\)\\|design\\|input_delay\\|li\\(b\\|cense\\)\\|net\\|" "output_delay\\|unconnected_ports\\)\\|name_design\\|optimize_design\\|" "p\\(lace_synthetic\\|ort_\\(a\\(nnotated_delay\\|rea\\|ttribute\\)\\|" "c\\(ell\\|lock\\|onstraint\\)\\|design\\(\\|_lib\\)\\|hierarchy\\|" "internal_loads\\|lib\\|multicycles\\|net\\|po\\(rt\\|wer\\)\\|re\\(" "ference\\|sources\\)\\|schedul\\(e\\|ing_constraints\\)\\|t\\(est\\|" "iming\\(\\|_requirements\\)\\)\\)\\)\\|set_\\(design\\|path\\)\\)\\|" "s\\(chedule\\|et_\\(a\\(nnotated_\\(check\\|delay\\)\\|ttribute\\)\\|" "boundary_optimization\\|c\\(lock_\\(skew\\|transition\\)\\|ycles\\)\\|" "d\\(isable_timing\\|ont_\\(touch\\(\\|_network\\)\\|use\\)\\|riv\\(" "e\\|ing_cell\\)\\)\\|e\\(co_\\(align\\|reuse\\|target\\|unique\\)\\|" "qual\\)\\|f\\(a\\(lse_path\\|nout_load\\)\\|ix_hold\\|latten\\|sm_\\(" "encoding\\(\\|_style\\)\\|minimize\\|order\\|state_vector\\)\\)\\|" "i\\(mplementation\\|nput_delay\\)\\|lo\\(ad\\|gic_\\(one\\|zero\\)\\)" "\\|m\\(ax_\\(area\\|c\\(apacitance\\|ycles\\)\\|d\\(elay\\|" "ynamic_power\\)\\|fanout\\|leakage_power\\|t\\(ime_borrow\\|" "ransition\\)\\)\\|ulticycle_path\\)\\|o\\(perating_conditions\\|" "utput_delay\\)\\|register_type\\|s\\(can_style\\|ignal_type\\|" "tructure\\)\\|test_methodology\\|unconnected\\|wire_load\\)\\|h\\)\\|" "u\\(n\\(alias\\|group\\|iquify\\|schedule\\)\\|pdate_lib\\)\\|w\\(" "hich\\|rite\\(\\|_\\(co\\(mpare_design_script\\|nstraints\\)\\|lib\\|" "p\\(arasitics\\|ower\\)\\|script\\|timing\\)\\)\\)" "\\)[ \t\n\\(]") 1 font-lock-keyword-face ) (list (concat ; "all_clocks" "all_cluster_cells" "all_clusters" "all_connected" ; "all_critical_cells" "all_critical_pins" "all_inputs" "all_outputs" ; "all_registers" "\\<\\(" "all_\\(c\\(l\\(ocks\\|uster\\(_cells\\|s\\)\\)\\|onnected\\|" "ritical_\\(cells\\|pins\\)\\)\\|inputs\\|outputs\\|registers\\)" "\\(\\s-\\|\\s(\\s)\\)\\)\\B") 1 font-lock-keyword-face ) (list (concat ; foreach find if while "\\(\\s-\\|\\s(\\|^\\)\\(" "if\\|f\\(oreach\\|ind\\)\\|while" "\\)\\(\\s-\\|\\s(\\)" ) 2 font-lock-keyword-face ) (list (concat ; "current_design" "current_instance" "\\<\\(" "current_\\(design\\|instance\\)" "\\)\\>") 1 font-lock-reference-face ) )) (defvar synopsys-font-lock-keywords-2 (list (list (concat ; "-analysis_effort" "-attributes" "-base_name" ; "-boundary_optimization" "-cell" "-cell_name" "-clock" ; "-clock_gating" "-cluster" "-connections" "-constraints" ; "-context" "-critical_range" "-dedicated_scan_ports" ; "-delay" "-depth" "-design" "-design_name" "-direction" ; "-drive" "-end" "-except" "-f" "-fall" "-fall_delay" "-flat" ; "-force" "-format" "-from" "-fsm" "-hier" "-hierarchy" ; "-hold" "-ideal" "-ignored" "-in_place" ; "-incremental_mapping" "-io_mode" "-library" "-load_delay" ; "-logic" "-map_effort" "-max" "-max_paths" ; "-max_scan_chain_length" "-methodology" "-min" ; "-minus_uncertainty" "-mode" "-modified" "-name" "-net" ; "-net_capacitance" "-net_timing" "-no_design_rule" ; "-no_disable" "-no_insert" "-no_map" "-no_timing" "-none" ; "-nosplit" "-nworst" "-only_design_rule" "-output" ; "-parameters" "-path" "-percentile" "-period" "-pin_load" ; "-plus_uncertainty" "-power" "-propagated" "-reference" ; "-rise" "-rise_delay" "-rules" "-scan" "-scan_chains" ; "-schedule" "-setup" "-skew" "-soft" "-sort" "-start" ; "-through" "-timing" "-timing_arcs" "-to" "-trim" "-type" ; "-uncertainty" "-ungroup_all" "-update" "-verbose" "-verify" ; "-waveform" "-weight" "-wire_load" "-work" "-worst" "\\B\\(" "-\\(a\\(dd_delay\\|ll\\(\\|_violators\\|owed\\)\\|nalysis_effort\\|" "ttributes\\)\\|b\\(ase_name\\|oundary_optimization\\)\\|c\\(ell\\(\\|" "_name\\)\\|l\\(ock\\(\\|_gating\\)\\|uster\\)\\|on\\(nections\\|" "straints\\|text\\)\\|ritical_range\\)\\|d\\(e\\(dicated_scan_ports\\|" "lay\\|pth\\|sign\\(\\|_name\\)\\)\\|irection\\|rive\\)\\|e\\(nd\\|" "xcept\\)\\|f\\(\\|all\\(\\|_delay\\)\\|lat\\|or\\(ce\\|mat\\)\\|rom\\|" "sm\\)\\|h\\(ier\\(\\|archy\\)\\|old\\)\\|i\\(deal\\|gnored\\|n\\(" "_place\\|cremental_mapping\\)\\|o_mode\\)\\|l\\(ibrary\\|o\\(" "ad_delay\\|gic\\)\\)\\|m\\(a\\(p_effort\\|x\\(\\|_\\(paths\\|" "scan_chain_length\\)\\)\\)\\|ethodology\\|in\\(\\|us_uncertainty\\)" "\\|od\\(e\\|ified\\)\\)\\|n\\(ame\\|et\\(\\|_\\(capacitance\\|" "timing\\)\\)\\|o\\(_\\(d\\(esign_rule\\|isable\\)\\|insert\\|map\\|" "timing\\)\\|ne\\|split\\)\\|worst\\)\\|o\\(nly_design_rule\\|utput\\)" "\\|p\\(a\\(rameters\\|th\\)\\|er\\(centile\\|iod\\)\\|in_load\\|" "lus_uncertainty\\|ower\\|ropagated\\)\\|r\\(eference\\|ise\\(\\|" "_delay\\)\\|ules\\)\\|s\\(c\\(an\\(\\|_chains\\)\\|hedule\\)\\|etup\\|" "kew\\|o\\(ft\\|rt\\)\\|tart\\)\\|t\\(hrough\\|iming\\(\\|_arcs\\)\\|" "o\\|rim\\|ype\\)\\|u\\(n\\(certainty\\|group_all\\)\\|pdate\\)\\|" "ver\\(bose\\|ify\\)\\|w\\(aveform\\|eight\\|ire_load\\|or\\(k\\|st\\)" "\\)\\)" "\\)\\>" ) 1 font-lock-variable-name-face ) )) (defvar synopsys-font-lock-keywords-3 (list (list (concat ; "medium" "low" "high" "verilog" "db" "vhdl" "sdf" "edif" ; "full_scan" "multiplexed_flip_flop" "top" "enclosed" "segmented" ; "max" "min" "full" "max_rise" "max_fall" "min_rise" "min_fall" ; "net" "cell" "port" "[-][a-z_]+[ \t]+\\(" "db\\|enclosed\\|full\\(\\|_scan\\)\\|high\\|low\\|m\\(ax\\(\\|" "_\\(fall\\|rise\\)\\)\\|edium\\|in\\(\\|_\\(fall\\|rise\\)\\)\\|" "ultiplexed_flip_flop\\)\\|segmented\\|top\\|v\\(erilog\\|hdl\\)" "\\|net\\|cell\\|port" "\\)[ \t\n\\]" ) 1 font-lock-type-face ) (list (concat ; actel_qbar_opto" "actel_seq_opto" "auto_link_disable" ; auto_link_options" "auto_wire_load_selection" "bc_enable_chaining" ; bc_enable_multi_cycle" "bc_enable_speculative_execution" ; bc_fsm_coding_style" "bc_time_all_sequential_op_bindings" ; bus_extraction_style" "bus_inference_style" "bus_naming_style" ; change_names_dont_change_bus_members" "change_names_update_inst_tree" ; command_log_file" "company" "compatibility_version" ; compile_assume_fully_decoded_three_state_busses" ; compile_create_mux_op_hierarchy" "compile_default_critical_range" ; compile_disable_area_opt_during_inplace_opt" ; compile_disable_hierarchical_inverter_opt" ; compile_dont_touch_annotated_cell_during_inplace_opt" ; compile_fix_multiple_port_nets" ; compile_ignore_area_during_inplace_opt" ; compile_ignore_footprint_during_inplace_opt" ; compile_implementation_selection" ; compile_inplace_changed_list_file_name" "compile_instance_name_prefix" ; compile_instance_name_suffix" "compile_mux_no_boundary_optimization" ; compile_negative_logic_methodology" "compile_no_new_cells_at_top_level" ; compile_ok_to_buffer_during_inplace_opt" ; compile_preserve_subdesign_interfaces" "compile_preserve_sync_resets" ; compile_update_annotated_delays_during_inplace_opt" ; compile_use_fast_delay_mode" "compile_use_low_timing_effort" ; context_check_status" "current_design" "current_instance" ; dc_shell_status" "default_name_rules" "design_library_file" "designer" ; duplicate_ports" "echo_include_commands" "enable_page_mode" ; exit_delete_filename_log_file" "filename_log_file" ; find_converts_name_lists" "find_ignore_case" "hdl_keep_licenses" ; hdl_naming_threshold" "hdl_preferred_license" "hdl_variables" ; hdlin_advisor_directory" "hdlin_auto_save_templates" ; hdlin_check_no_latch" "hdlin_dont_infer_mux_for_resource_sharing" ; hdlin_enable_advisor" "hdlin_ff_always_async_set_reset" ; hdlin_ff_always_sync_set_reset" "hdlin_files" ; hdlin_hide_resource_line_numbers" "hdlin_infer_mux" ; hdlin_keep_feedback" "hdlin_keep_inv_feedback" "hdlin_mux_size_limit" ; hdlin_reg_report_length" "hdlin_replace_synthetic" ; hdlin_report_inferred_modules" "hdlin_resource_allocation" ; hdlin_resource_implementation" "hdlin_source_to_gates_mode" ; hdlin_sync_set_reset" "hdlin_synch_set_reset" ; hdlin_translate_off_skip_text" "link_force_case" "link_library" ; port_complement_naming_style" ; reoptimize_design_changed_list_file_name" "sdfin_fall_cell_delay_type" ; sdfin_fall_net_delay_type" "sdfin_min_fall_cell_delay" ; sdfin_min_fall_net_delay" "sdfin_min_rise_cell_delay" ; sdfin_min_rise_net_delay" "sdfin_rise_cell_delay_type" ; sdfin_rise_net_delay_type" "sdfin_top_instance_name" ; sdfout_allow_non_positive_constraints" "sdfout_min_fall_cell_delay" ; sdfout_min_fall_net_delay" "sdfout_min_rise_cell_delay" ; sdfout_min_rise_net_delay" "sdfout_time_scale" ; sdfout_top_instance_name" "sdfout_write_to_output" "search_path" ; shell_prompt" "suppress_errors" "synlib_dont_get_license" ; syntax_check_status" "synthetic_library" "target_library" ; uniquify_naming_style" "verbose_messages" ; edifin_* edifout_* verilogout_* mentor_* vhdlout_* vhdllib_* write_test_* ; test_scan_* "\\<\\(" "a\\(ctel_\\(qbar_opto\\|seq_opto\\)\\|uto_\\(link_\\(disable\\|" "options\\)\\|wire_load_selection\\)\\)\\|b\\(c_\\(enable_\\(" "chaining\\|multi_cycle\\|speculative_execution\\)\\|" "fsm_coding_style\\|time_all_sequential_op_bindings\\)\\|us_\\(" "extraction_style\\|inference_style\\|naming_style\\)\\)\\|c\\(" "hange_names_\\(dont_change_bus_members\\|update_inst_tree\\)\\|" "o\\(m\\(mand_log_file\\|p\\(a\\(ny\\|tibility_version\\)\\|ile_\\(" "assume_fully_decoded_three_state_busses\\|create_mux_op_hierarchy" "\\|d\\(efault_critical_range\\|isable_\\(" "area_opt_during_inplace_opt\\|hierarchical_inverter_opt\\)\\|" "ont_touch_annotated_cell_during_inplace_opt\\)\\|" "fix_multiple_port_nets\\|i\\(gnore_\\(area_during_inplace_opt\\|" "footprint_during_inplace_opt\\)\\|mplementation_selection\\|n\\(" "place_changed_list_file_name\\|stance_name_\\(prefix\\|suffix\\)" "\\)\\)\\|mux_no_boundary_optimization\\|n\\(" "egative_logic_methodology\\|o_new_cells_at_top_level\\)\\|" "ok_to_buffer_during_inplace_opt\\|preserve_s\\(" "ubdesign_interfaces\\|ync_resets\\)\\|u\\(" "pdate_annotated_delays_during_inplace_opt\\|se_\\(" "fast_delay_mode\\|low_timing_effort\\)\\)\\)\\)\\)\\|" "ntext_check_status\\)\\|urrent_\\(design\\|instance\\)\\)\\|d\\(" "c_shell_status\\|e\\(fault_name_rules\\|sign\\(_library_file\\|" "er\\)\\)\\|uplicate_ports\\)\\|e\\(cho_include_commands\\|" "nable_page_mode\\|xit_delete_filename_log_file\\)\\|fi\\(" "lename_log_file\\|nd_\\(converts_name_lists\\|ignore_case\\)\\)\\|" "hdl\\(_\\(keep_licenses\\|naming_threshold\\|preferred_license\\|" "variables\\)\\|in_\\(a\\(dvisor_directory\\|uto_save_templates\\)" "\\|check_no_latch\\|dont_infer_mux_for_resource_sharing\\|" "enable_advisor\\|f\\(f_always_\\(async_set_reset\\|sync_set_reset" "\\)\\|iles\\)\\|hide_resource_line_numbers\\|infer_mux\\|keep_\\(" "feedback\\|inv_feedback\\)\\|mux_size_limit\\|re\\(g_report_length" "\\|p\\(lace_synthetic\\|ort_inferred_modules\\)\\|source_\\(" "allocation\\|implementation\\)\\)\\|s\\(ource_to_gates_mode\\|" "ync\\(_set_reset\\|h_set_reset\\)\\)\\|translate_off_skip_text\\)" "\\)\\|link_\\(force_case\\|library\\)\\|" "port_complement_naming_style\\|" "reoptimize_design_changed_list_file_name\\|s\\(df\\(in_\\(fall_\\(" "cell_delay_type\\|net_delay_type\\)\\|min_\\(fall_\\(cell_delay\\|" "net_delay\\)\\|rise_\\(cell_delay\\|net_delay\\)\\)\\|rise_\\(" "cell_delay_type\\|net_delay_type\\)\\|top_instance_name\\)\\|out_" "\\(allow_non_positive_constraints\\|min_\\(fall_\\(cell_delay\\|" "net_delay\\)\\|rise_\\(cell_delay\\|net_delay\\)\\)\\|t\\(" "ime_scale\\|op_instance_name\\)\\|write_to_output\\)\\)\\|" "earch_path\\|hell_prompt\\|uppress_errors\\|yn\\(" "lib_dont_get_license\\|t\\(ax_check_status\\|hetic_library\\)\\)" "\\)\\|target_library\\|uniquify_naming_style\\|verbose_messages" "\\|write_test_[a-z_]+\\|vhdlout_[a-z_]+\\|vhdllib_[a-z_]+\\|" "verilogout_[a-z_]+\\|mentor_[a-z_]+\\|edif\\(out\\|in\\)_[a-z_]+" "\\|db2sge_[a-z_]+\\|test_\\(scan\\|clock\\)_[a-z_]+" "\\)\\>") 1 font-lock-reference-face ) ) ) (defvar synopsys-font-lock-highlight-level 3 "Specify the level of complexity to use when highlighting Synopsys code. The lower the value, the less fontifying is done. Possible values are: nil - no keyword highlighting, only comments and strings are fontified 1 - only synopsys commands (and comments, strings) 2 - synopsys commands, options, comments and strings 3 - synopsys commands, options, common option values, and common synopsys variables are highlighted Fontifying (i.e. highlighting is only done if font-lock mode is specified.") (defun synopsys-font-lock-initialize () "Set the Synopsys font-lock regexp to the level requested by the user." (cond ((eq synopsys-font-lock-highlight-level nil) (setq synopsys-font-lock-keywords nil)) ((eq synopsys-font-lock-highlight-level 1) (setq synopsys-font-lock-keywords synopsys-font-lock-keywords-1)) ((eq synopsys-font-lock-highlight-level 2) (setq synopsys-font-lock-keywords (append synopsys-font-lock-keywords-1 synopsys-font-lock-keywords-2))) (t (setq synopsys-font-lock-keywords (append synopsys-font-lock-keywords-1 synopsys-font-lock-keywords-2 synopsys-font-lock-keywords-3))) )) ;; add the hook so that font-lock will be automatically setup ;; first, the keywords are initialized according to the ;; synopsys-font-lock-highlight-level, then the font-lock-defaults ;; variable is initialized (add-hook 'synopsys-mode-hook '(lambda () (synopsys-font-lock-initialize) (make-local-variable 'font-lock-defaults) (setq font-lock-defaults '(synopsys-font-lock-keywords nil)))) ;;; Support for Xemacs??? ;;; (defsubst synopsys-xemacs-p () (string-match "XEmacs\\|Lucid" emacs-version)) (defvar del-back-ch (car (append (where-is-internal 'delete-backward-char) (where-is-internal 'backward-delete-char-untabify))) "Character generated by key bound to delete-backward-char.") (and (vectorp del-back-ch) (= (length del-back-ch) 1) (setq del-back-ch (aref del-back-ch 0))) (if (synopsys-xemacs-p) (progn ;; "Active regions" are on: use region only if active ;; "Active regions" are off: use region unconditionally (defun synopsys-use-region-p () (if zmacs-regions (mark) t)) (defun synopsys-mark-active () (mark))) (defun synopsys-use-region-p () (if transient-mark-mode mark-active t)) (defun synopsys-mark-active () mark-active)) ;;; Auto comment formating and auto indent toggling (defun synopsys-toggle-auto-indent () "Toggle the state of `synopsys-auto-indent'. When set, this variable will indent every line after hitting LFD" (interactive) (setq synopsys-auto-indent (not synopsys-auto-indent)) (message "Newlines will %scause automatic indentation now." (if synopsys-auto-indent "" "not "))) (defun synopsys-toggle-auto-cformat () "Toggle the state of `synopsys-auto-cformat'. When set, this variable will format and fill comments after the comment has ended and after hitting LFD" (interactive) (setq synopsys-auto-cformat (not synopsys-auto-cformat)) (message "Comment will %sbe automatically filled/formatted now." (if synopsys-auto-cformat "" "not "))) (defun synopsys-toggle-auto-tab () "Toggle the state of `synopsys-tab-always-indent'. When set, tab will automatically indent the current line. Inserting a real tab requires 'quoting'. See the explanation for `synopsys-tab-always-indent' for more details." (interactive) (setq synopsys-tab-always-indent (not synopsys-tab-always-indent)) (message "Tab key will %sbe indent the current line." (if synopsys-tab-always-indent "" "not "))) (defun synopsys-toggle-auto-backslash () "Toggle the state of `synopsys-auto-backslash'. When the variable is set, long lines (longer than `fill-column' will be split into several lines with backslashes." (interactive) (setq synopsys-auto-backslash (not synopsys-auto-backslash)) (message "Long lines will %sbe split into shorter lines." (if synopsys-auto-backslash "" "not "))) ;;; This page contains the basic setup for synopsys-mode - the autoload ;;; comment allows the loaddefs.el file to be updated. (Thanks to B Silveira) ;;;###autoload (defun synopsys-mode () "Major mode for editing Synopsys DC Shell scripts. This mode helps write and analyze DC shell scripts by adding indentation and font-lock support. Tab key indent the current line of Synopsys code (can be disabled with the `synopsys-tabs-always-indent' variable. Comments are delimited with /* ... */. Note: there MUST be some whitespace character before the comment starter and before the comment ender for them to be recognized! Whitespace is either a space, a tab, or a newline. The following are valid comments: /* valid comments */ /* comment */ The following are invalid: blah blah/* asdf asd */ bal blah /* asdfasdf*/ find(pin, top/*) Comment style is controlled via the `synopsys-comment-style' variable. See the documentation of this variable for more details. It controls the indentation and formatting of comments (although this depends on the setting of `synopsys-auto-indent' and `synopsys-auto-cformat'. Five different comment styles are supported. Paragraphs are separated by blank lines only. Delete converts tabs to spaces as it moves back. Indentation is automated by default, but can be disabled via the `synopsys-auto-indent' variable. Long lines can be automatically split (with the continuation backslash added) if the `synopsys-auto-backslash' variable is enabled. See the documentation that follows. \\{synopsys-mode-map} Variables controlling indentation style: synopsys-tab-always-indent Non-nil means TAB in synopsys mode should always reindent the current line, regardless of where in the line point is when the TAB command is used. Default is t. synopsys-auto-indent Non-nil means a newline will automatically indent the current line, and place the cursor on the following line at the proper point of indentation. Default is t. synopsys-indent-level Indentation of synopsys statements within surrounding block. The surrounding block's indentation is the indentation of the line on which the open-brace appears (after if, while, foreach). synopsys-continued-statement-offset Extra indentation given to a statement that is continued with a backslash. This extra indentation is given to the 2nd and subsequent extra lines of a continued statement. synopsys-continued-brace-offset Extra indentation given to a brace that starts a substatement. synopsys-brace-offset Extra indentation for line if it starts with an open brace. synopsys-brace-imaginary-offset An open brace following other text is treated as if it were this far to the right of the start of its line. Settings for K&R and BSD indentation styles are synopsys-indent-level 5 8 synopsys-continued-statement-offset 5 8 synopsys-brace-offset -5 -8 You can select the indentation style (which includes the indent-level, and all the offset variables listed above) with the \\[set-synopsys-style] command. By default, this mode has automatic indentation, comment filling, and long line splitting. These features can be disabled with the following variables: synopsys-auto-indent Enables/disables automatic indentation of lines after a newline. Default t. synopsys-auto-cformat Enables/disables automatic filling of comments after the comment end ( */) and a newline are entered. Default t. See synopsys-auto-cformat for more details. synopsys-auto-backslash Enables/disables automatic splitting of lines that are longer than `fill-column'. Default t. synopsys-comment-style Chooses one of 5 different styles for multi-line comments. These styles are described in the documentation for this variable. Type \\[describe-variable] synopsys-comment-style for more details. Indentation and automatic formatting can be enabled/disabled via a pull-down menu, if its supported in your version of emacs. You can use the `synopsys-backslash-region' command to split lines if necessary, or to remove the backslash continuation. This function is also available on the pull-down menu. The comment-region and uncomment-region are useful functions for blocking out sections of code. Indenting of comments is controlled via the `synopsys-comment-style' variable. Fontification with font-lock is supported. Personally, I also use lazy-lock, so I like having a lot of things highlighted. This helps check for common spelling mistakes (if a word doesn't highlight, likely I've made a finger fumble). By default, maximum fontification is enabled (if font-lock mode is turned on). By changing the setting of `synopsys-font-lock-highlight-level' variable you can control the amount of fontification you get. See the documentation of this variable to have a better idea of its setting. Turning on synopsys mode calls the value of the variable synopsys-mode-hook with no args, if that value is non-nil. To submit a problem/bug report, enter \\[synopsys-submit-bug-report] from the synopsys-mode buffer that experienced the problem. This will automatically set up a mail buffer with the version number and some key variables. You just need to add a detailed description of the problem, along with a reproducable test case, then send the message." (interactive) (kill-all-local-variables) (use-local-map synopsys-mode-map) (setq major-mode 'synopsys-mode) (setq mode-name "Synopsys") (setq local-abbrev-table synopsys-mode-abbrev-table) (set-syntax-table synopsys-mode-syntax-table) (make-local-variable 'paragraph-start) (setq paragraph-start (concat "$\\|" page-delimiter)) ;; sentence end -search for an end of line, but one that isn't a ;; continued statement (i.e. has a backslash) This doesn't work ;; all the time - it fails on the end of a paragraph! Can't figure ;; out how to fix this, and doesn't seem to cause real problems (make-local-variable 'sentence-end) (setq sentence-end "[^\\]\n") (make-local-variable 'paragraph-separate) (setq paragraph-separate paragraph-start) (make-local-variable 'paragraph-ignore-fill-prefix) (setq paragraph-ignore-fill-prefix t) ;;;;;;------- this seems to be a problem, needs rewrite ; (make-local-variable 'fill-paragraph-function) ; (setq fill-paragraph-function 'synopsys-fill-paragraph) ;; Adaptive fill mode gets in the way of auto-fill, ;; and should make no difference for explicit fill ;; because lisp-fill-paragraph should do the job. (make-local-variable 'adaptive-fill-mode) (setq adaptive-fill-mode nil) (make-local-variable 'indent-line-function) (setq indent-line-function 'synopsys-indent-line) (make-local-variable 'indent-region-function) (setq indent-region-function 'synopsys-indent-region) (make-local-variable 'require-final-newline) (setq require-final-newline t) (make-local-variable 'comment-start) (setq comment-start "/*") (make-local-variable 'comment-end) (setq comment-end "*/") (make-local-variable 'comment-column) (setq comment-column 38) (make-local-variable 'comment-start-skip) ;; comments must start with a whitespace, cuz synopsys has the option ;; of using the * character as a glob character for specifying cells ;; or pins, etc. For example, you could say find pin junk/*/b* -- this ;; looks like the start of a comment but its not! This is controlled via ;; other regexps instead of here. The special synopsys-parse-partial-sexp ;; can help identify real versus fake comments (setq comment-start-skip "/\\*+ *") (make-local-variable 'comment-indent-function) (setq comment-indent-function 'synopsys-comment-indent) (make-local-variable 'comment-multi-line) (setq comment-multi-line t) (if (string-match "Xemacs" emacs-version) (progn (if (and current-menubar (not (assoc "Synopsys" current-menubar))) (progn (set-buffer-menubar (copy-sequence current-menubar)) (add-submenu nil synopsys-xemacs-menu))))) (make-local-variable 'parse-sexp-ignore-comments) (setq parse-sexp-ignore-comments t) ; (setq parse-sexp-ignore-comments nil) (make-local-variable 'font-lock-keywords) ;; font-lock-fontify-region-function over-rides the default function. ;; this is required because we need to use our own version of font (make-local-variable 'font-lock-fontify-region-function) (setq font-lock-fontify-region-function 'synopsys-font-lock-fontify-region) (condition-case nil (progn (require 'font-lock) (or (fboundp 'font-lock-default-fontify-region) (message "You have an obsolete `font-lock' package! Install a newer version. Without the new version, fontification may get confused with some Synopsys constructs."))) (error nil)) (run-hooks 'synopsys-mode-hook)) (defconst comment-start-re "/\\*" ) (defconst comment-end-re "\\*/" ) (defconst comment-start-with-delimiters-re (concat "\\(^[ \t]*\\|[ \t]+\\)" comment-start-re )) (defconst comment-end-with-delimiters-re (concat "\\(^\\|[ \t]+\\)" comment-end-re )) (defconst comment-start-at-bol-re (concat "^" comment-start-re)) ;;; This page handles comment filling and indent-for-comment ;; This is used by indent-for-comment ;; to decide how much to indent a comment in synopsys code ;; based on its context. (defun synopsys-comment-indent () (if (looking-at comment-start-at-bol-re) 0 ;Existing comment at bol stays there. (let ((opoint (point))) (save-excursion (beginning-of-line) (cond ((looking-at (concat "[ \t]*}[ \t]*\\($\\|" comment-start-re "\\)")) ;; A comment following a solitary close-brace ;; should have only one space. (search-forward "}") (1+ (current-column))) ((progn (goto-char opoint) (skip-chars-backward " \t") (and (= comment-column 0) (bolp))) ;; If comment-column is 0, and nothing but space ;; before the comment, align it at 0 rather than 1. 0) (t (max (1+ (current-column)) ;Else indent at comment column comment-column))))))) ; except leave at least ; one space. (defun synopsys-fill-paragraph (&optional arg fill-partial) "Like \\[fill-paragraph] but handle synopsys comments. If any of the current line is a comment or within a comment, fill the comment or the paragraph of it that point is in, preserving the comment indentation or line-starting decorations. The first optional argument, arg, is used if you want to justify the paragraph. The second optional argument is used if you want to fill only the portion of the comment from the current point, back to the beginning." (interactive "P") (let* ((comment-start-place (save-excursion ;; search for beginning of the comment, starting from here, ;; going back all the way to the beginning of the buffer (let (end_flag) (while (not end_flag) ;; search back for the comment start (if (and ;; find the beginning of the comment (re-search-backward comment-start-re (point-min) t) ;; make sure we're no longer inside a comment ;; (ensures we didn't stumble across a bogus ;; comment start) (not (synopsys-in-comment-p))) (progn (setq end_flag t) ;; if we're at the comment start, need to move ;; forward 1 char to get proper starting ;; position, if we're not looking directly at ;; a comment, we must be separated by ;; whitespace on this line, so jump to the ;; beginning of the comment (skip-chars-forward " \t") ;; found beginning of comment so set the start place (setq comment-start-place (point))) ;; didn't yet find the start of the comment, so try again nil) ) (point)))) (font-lock-is-on (fboundp 'lazy-lock-defer-driven)) last-line-column ;; search for the end of the comment. If we don't find it, its ok, ;; just set the last-line variable to nil (last-line (save-excursion (if (search-backward comment-end comment-start-place t) (progn (goto-char (match-end 0)) ;; check to see its a real comment ender, not a bogus one (if (synopsys-in-comment-p) nil (setq last-line-column (current-column)) (point))) ;; if we are allowed to look for the entire paragraph, then ;; search forward for the paragraph end (if (and (not fill-partial) (re-search-forward comment-end-with-delimiters-re nil t)) (progn (goto-char (match-end 0)) (if (synopsys-in-comment-p) nil (setq last-line-column (current-column)) (point))) nil)))) ;; find out if comment is currently multi-line, or likely to become ;; multi-line after filling. We need to know this, so we can apply ;; the appropriate comment style (multi-line-comment-p (save-excursion (let ((stop (or last-line (point)))) (if comment-start-place (goto-char comment-start-place) (goto-char (point-min))) (forward-line 1) (if (or (and last-line (< (point) last-line)) (< (point) stop) (and (not last-line) fill-partial)) t nil))))) ;; if we didn't find the beginning of the comment, we shouldn't even ;; be using this function, so do nothing!!! (if comment-start-place (progn (if font-lock-is-on (progn (lazy-lock-defer-driven t) )) (let ((fill-prefix ;; figure out what the fill-prefix should be. (save-excursion (goto-char comment-start-place) (let ((max-whitespace (- fill-column 25))) (if (< max-whitespace 0) (setq max-whitespace 0)) (if (> (current-column) max-whitespace) (concat (make-string max-whitespace ?\ ) (cond ((= synopsys-comment-style 5) "") ((= synopsys-comment-style 4) "** ") ((= synopsys-comment-style 3) " * ") (t " "))) (concat (make-string (current-column) ?\ ) (cond ((= synopsys-comment-style 5) "") ((= synopsys-comment-style 4) "** ") ((= synopsys-comment-style 3) " * ") (t " "))) )))) (paragraph-start ;; Lines containing just a comment start or just an end ;; should not be filled into paragraphs they are next to. (concat paragraph-start "\\|" comment-start-with-delimiters-re "$\\|" comment-end-with-delimiters-re "$")) (paragraph-separate (concat paragraph-separate "\\|" comment-start-with-delimiters-re "$\\|" comment-end-with-delimiters-re "$")) (chars-to-delete 0)) ;; if we have a multi-line comment or a single line comment that ;; will likely become multi-line after filling, see if we need to ;; isolate the comment starter on its own line. This is needed for ;; all comment styles except for style 2 (if (or multi-line-comment-p (and last-line (> last-line-column fill-column)) (> (current-column) fill-column)) (save-excursion (let ((end (point))) (setq multi-line-comment-p t) (goto-char (+ 2 comment-start-place)) (if (= synopsys-comment-style 2) nil (skip-chars-forward " \t") (if (and (eolp) (< (point) end)) nil (newline) (and (< (point) end) (insert fill-prefix)) ;; need to account for all these new characters we've ;; added so update last-line to include the newline, plus ;; the fill-prefix (if last-line (setq last-line (+ 1 (current-column) last-line)))))))) ;; Don't fill the comment together with the code following it. So ;; temporarily exclude everything before the comment-start and ;; everything after the comment ends. No matter what style of comment ;; we're dealing with the comment starter is outside of the narrowed ;; region (save-restriction (let ((column (current-column))) (narrow-to-region (save-excursion (goto-char comment-start-place) (setq column (current-column)) ;; if we have a multi-line comment, should ;; exclude filling of the first line for ;; all comment styles except style 2 (others ;; have the 1st line containing only the ;; comment start. (if (and multi-line-comment-p (not (= synopsys-comment-style 2))) (progn (forward-line 1) (point)) (prog1 (point) (insert-char ?\ column) (setq chars-to-delete column)))) (save-excursion (if last-line (if (or (= synopsys-comment-style 2) (not multi-line-comment-p)) (goto-char (+ last-line column)) (goto-char last-line)) (point))))) (untabify (point-min) (point-max)) (fill-paragraph arg) (save-excursion ;; Delete the chars we inserted to avoid overwriting the code ;; before the comment (goto-char (point-min)) (if (> chars-to-delete 0) (delete-region (point) (+ (point) chars-to-delete))) ;; Find the comment ender (should be on the 2nd last line of ;; buffer, given the narrowing) and figure out if it should be ;; combined with comment, or left on its own line. This depends ;; upon the `synopsys-comment-style' variable. (if last-line (progn (goto-char (point-max)) (forward-line -1) ;; Search for a lone comment ender. Of course the ;; comment ender will have a fill-prefix in front of ;; it, but if there is nothing between the fill-prefix ;; and the comment-end, delete the fill-prefix. If ;; synopsys-comment-style 2, then merge the comment-end ;; with the previous line. (if (looking-at (substring (concat fill-prefix comment-end-re) 0)) ;; delete the fill prefix, leaving just comment ender (progn (delete-region (progn (beginning-of-line) (point)) (progn (search-forward comment-end nil 'move) (goto-char (match-beginning 0)))) (if (= synopsys-comment-style 2) (progn (forward-line -1) (let ((fill-column (+ fill-column 9999))) (fill-region-as-paragraph (point) (point-max)))))) ;; not a lone comment, so separate comment ender from comment ;; except if style 2 (re-search-forward comment-end-with-delimiters-re) (forward-char -2) (if (or (= synopsys-comment-style 2) (not multi-line-comment-p)) nil (newline))))) )) (cond ((not last-line) ;; if we haven't yet got a comment-ender, then we should ;; add the fill-prefix to the last line to make it easier ;; for the user nil) (multi-line-comment-p ;; need to properly indent the comment ender if it was a ;; multi-line comment (synopsys-indent-line))) ))))) ;;; Electric brace, newline, etc. (defun electric-synopsys-newline () "Insert a newline and correct line's indentation. Indentation occurs only if `synopsys-auto-indent' is set. Comments are automatically filled if `synopsys-auto-cformat' is set." (interactive) (if synopsys-auto-indent ; (if (and (synopsys-in-comment-p) (not synopsys-auto-cformat)) ; nil ; (synopsys-indent-line))) (synopsys-indent-line)) (if (not (eolp)) (progn (newline) (if synopsys-auto-indent ; (if (and (synopsys-in-comment-p) (not synopsys-auto-cformat)) ; nil ; (synopsys-indent-line)))) (synopsys-indent-line))) (let* (add-prefix (add-line (progn (save-excursion (if (not (synopsys-in-comment-p)) ;; if not currently inside a comment (progn ;; check to see if line is too long, if so, add ;; backslashes (if synopsys-auto-backslash (synopsys-slash-it)) (end-of-line) (skip-chars-backward " \t") ;; check to see if we're at the end of a ;; comment. If so, fill it in nicely. If not, just ;; add a newline. (backward-char 2) (if (and (looking-at comment-end-re) (synopsys-in-comment-p) synopsys-auto-cformat) (progn (end-of-line) (synopsys-fill-paragraph nil nil) nil ) t ) ) (progn (if synopsys-auto-cformat (progn (synopsys-format-comment-if-necessary) (setq add-prefix t))) nil )))))) (if add-line (newline) (forward-line 1) (if add-prefix (cond ((= synopsys-comment-style 4) (insert "** ")) ((= synopsys-comment-style 3) (insert " * "))))) (if synopsys-auto-indent ; (if (and (synopsys-in-comment-p) (not synopsys-auto-cformat)) ; nil ; (synopsys-indent-line))))) (synopsys-indent-line)))) ) (defun synopsys-in-comment-p () "Return true if in a comment" (let ((state (save-excursion (synopsys-parse-partial-sexp (point-min) (point))))) (nth 4 state)) ) (defun synopsys-format-comment-if-necessary () "Fill in the comment to the proper line length" (interactive) (end-of-line) (synopsys-fill-paragraph nil t) ) (defun synopsys-slash-it () "Add a backslash continuation character if the line is too long. Lines are allowed to extend up to the fill-column. Backslashes are only added to the non-comment section of the line. Comments that extend past the fill-column are left alone. \\[synopsys-fill-paragraph] will take care of comments that extend too far." (interactive) (end-of-line) (let ((beg (save-excursion (beginning-of-line) (point)))) (synopsys-backward-to-noncomment beg) (while (> (current-column) fill-column) (progn (while (> (current-column) 0) (re-search-backward "\\s-\\|\(\\|," beg t) (skip-chars-backward " \t") (if (< (current-column) fill-column ) (progn (forward-char 1) (indent-to (- fill-column 1)) (insert "\\") (newline) (if synopsys-auto-indent (synopsys-indent-line)) (beginning-of-line) ))) (end-of-line))) (end-of-line))) (or (fboundp 'uncomment-region) (defun uncomment-region (beg end) (interactive "r") (comment-region beg end -1))) (defun synopsys-indent-command (&optional whole-exp) "Indent current line as synopsys code, or in some cases insert a tab character. If `synopsys-tab-always-indent' is non-nil (the default), always indent current line. Otherwise, indent the current line only if point is at the left margin or in the line's indentation; otherwise insert a tab. A numeric argument, regardless of its value, means indent rigidly all the lines of the expression starting after point so that this line becomes properly indented. The relative indentation among the lines of the expression are preserved." (interactive "P") (if whole-exp ;; If arg, always indent this line as synopsys ;; and shift remaining lines of expression the same amount. (let ((shift-amt (synopsys-indent-line)) beg end) (save-excursion (if synopsys-tab-always-indent (beginning-of-line)) ;; Find beginning of following line. (save-excursion (forward-line 1) (setq beg (point))) ;; Find first beginning-of-sexp for sexp extending past this line. (while (< (point) beg) (forward-sexp 1) (setq end (point)) (skip-chars-forward " \t\n"))) (if (> end beg) (indent-code-rigidly beg end shift-amt "#"))) (if (and (not synopsys-tab-always-indent) (save-excursion (skip-chars-backward " \t") (not (bolp)))) (insert-tab) (synopsys-indent-line)))) (defun synopsys-indent-line () "Indent current line as synopsys code. Return the amount the indentation changed by." (let ((indent (calculate-synopsys-indent nil)) beg shift-amt (case-fold-search nil) (pos (- (point-max) (point)))) (beginning-of-line) (setq beg (point)) (cond ((eq indent nil) ; don't do anything cuz we're not supposed to indent (setq indent (current-indentation))) ((eq indent t) ; found a comment, so use special indent command (setq indent (calculate-synopsys-indent-within-comment))) ; indent this command (t (skip-chars-forward " \t") (if (listp indent) (setq indent (car indent))) (cond ((and (looking-at "else\\b") (not (looking-at "else\\s_"))) (setq indent (save-excursion (synopsys-backward-to-start-of-if) (current-indentation)))) ((and (looking-at "}[ \t]*else\\b") (not (looking-at "}[ \t]*else\\s_"))) (setq indent (save-excursion (forward-char) (backward-sexp) (synopsys-backward-to-start-of-if) (current-indentation)))) ((= (following-char) ?}) (setq indent (- indent synopsys-indent-level))) ((= (following-char) ?{) (setq indent (+ indent synopsys-brace-offset)))))) (skip-chars-forward " \t") (setq shift-amt (- indent (current-column))) (if (zerop shift-amt) (if (> (- (point-max) pos) (point)) (goto-char (- (point-max) pos))) (delete-region beg (point)) (indent-to indent) ;; If initial point was within line's indentation, position after ;; the indentation. Else stay at same point in text. (if (> (- (point-max) pos) (point)) (goto-char (- (point-max) pos)))) shift-amt)) (defun calculate-synopsys-indent (&optional parse-start) "Return appropriate indentation for current line as synopsys code. In usual case returns an integer: the column to indent to. Returns nil if line starts inside a string, t if in a comment." (save-excursion (beginning-of-line) (let ((indent-point (point)) (case-fold-search nil) state indent_val containing-sexp) ;; goto the beginning of this function or to the parse-start point ;; if specified. This is needed to be able to count all the nested ;; parentheses (if parse-start (goto-char parse-start) (beginning-of-defun)) ;; find out if this line is in a series of parentheses (while (< (point) indent-point) (setq parse-start (point)) (setq state (synopsys-parse-partial-sexp (point) indent-point 0)) (setq containing-sexp (car (cdr state)))) (cond ((or (nth 3 state) (nth 4 state)) ;; return nil or t if should not change this line, cuz its ;; in a comment (nth 4 state)) ;; error check, just added for indenting of very 1st line of ;; the buffer. Don't really understand why ;; parse-partial-sexp gives a nil value for the first line ;; only, but this provides a work around. ((eq (nth 0 state) nil) nil ) ;; check if it's inside parens ((> (nth 0 state) 0) (goto-char (nth 1 state)) (setq indent_val (+ (current-indentation) synopsys-indent-level)) (goto-char indent-point) (beginning-of-line) (backward-char 1) (if (= (preceding-char) ?\\) (+ indent_val synopsys-continued-statement-offset) indent_val)) ((null containing-sexp) ;; line isn't inside parens, so..... (backward-char 1) (if (= (preceding-char) ?\\) ;; found a continued line, so use previous line's ;; indentation, plus a little bit more (progn (synopsys-backward-to-start-of-backslashed-exp) (+ (current-indentation) synopsys-continued-statement-offset)) ;; line must be top level, so no indent is allowed 0 )))))) (defun calculate-synopsys-indent-after-brace () "Return the proper synopsys indent for the first line after an open-brace. This function is called with point before the brace." ;; For open brace in column zero, don't let statement ;; start there too. If synopsys-indent-level is zero, ;; use synopsys-brace-offset + synopsys-continued-statement-offset instead. ;; For open-braces not the first thing in a line, ;; add in synopsys-brace-imaginary-offset. (+ (if (and (bolp) (zerop synopsys-indent-level)) (+ synopsys-brace-offset synopsys-continued-statement-offset) synopsys-indent-level) ;; Move back over whitespace before the openbrace. ;; If openbrace is not first nonwhite thing on the line, ;; add the synopsys-brace-imaginary-offset. (progn (skip-chars-backward " \t") (if (bolp) 0 synopsys-brace-imaginary-offset)) ;; If the openbrace is preceded by a parenthesized exp, ;; move to the beginning of that; ;; possibly a different line (progn (if (eq (preceding-char) ?\)) (forward-sexp -1)) ;; Get initial indentation of the line we are on. (current-indentation)))) (defun calculate-synopsys-indent-within-comment () "Return the indentation amount for line inside a multi-line comment." (save-excursion (let ((end) ) ;; go back to the previous line and find out how much it was indented (beginning-of-line) (skip-chars-backward " \t\n") (setq end (point)) (beginning-of-line) (skip-chars-forward " \t") ;; if the previous line was the start of the comment, figure out how ;; much to indent based on the comment start position, plus the number ;; of stars. If not the start of the block comment, then just use ;; the previous lines indent ;; (note: I may need to rewrite- what if the comment-start is false? ;; maybe should test to see if it really is the comment start??? (if (re-search-forward comment-start-re end t) (goto-char (+ (match-beginning 0) (cond ((= synopsys-comment-style 5) 0) ((= synopsys-comment-style 4) 0) ((= synopsys-comment-style 3) 1) (t 3))))) ;; set comment indent to previous lines indent ;; over-ride this value if the previous comment line was placed ;; past the comment-column. This takes care ;; of blocked comments formatted via synopsys-fill-paragraph (let ((comment-indent (current-column))) (if (> comment-indent comment-column) (+ comment-column (cond ((= synopsys-comment-style 5) 0) ((= synopsys-comment-style 4) 0) ((= synopsys-comment-style 3) 1) (t 3))) comment-indent))))) (defun synopsys-backward-to-noncomment (lim) "Move back to a non-commented part of the code" (let (opoint stop) (while (not stop) (skip-chars-backward " \t\n\f" lim) (setq opoint (point)) (if (and (>= (point) (+ 2 lim)) (save-excursion (forward-char -2) (synopsys-in-comment-p))) (re-search-backward comment-start-re lim 'move) (setq stop (or (<= (point) lim) (save-excursion (beginning-of-line) (skip-chars-forward " \t") ))) (or stop (beginning-of-line)))))) (defun synopsys-backward-to-start-of-backslashed-exp (&optional limit) "Move to the starts of the last statement which has a continuation backslash character" (or limit (setq limit (save-excursion (beginning-of-defun) (point)))) (let ((test-flag 1)) (while (and (>= (point) limit) (not (zerop test-flag))) (beginning-of-line) (forward-char -1) (if (eq (preceding-char) ?\\) nil (setq test-flag 0) (forward-char 1) (skip-chars-forward " \t"))))) (defun synopsys-backward-to-start-of-if (&optional limit) "Move to the start of the last \"unbalanced\" `if'." (or limit (setq limit (save-excursion (beginning-of-defun) (point)))) (let ((if-level 1) (case-fold-search nil)) (while (and (not (bobp)) (not (zerop if-level))) (backward-sexp 1) (cond ((and (looking-at "else\\b") (not (looking-at "else\\s_"))) (setq if-level (1+ if-level))) ((and (looking-at "if\\b") (not (looking-at "if\\s_"))) (setq if-level (1- if-level))) ((< (point) limit) (setq if-level 0) (goto-char limit)))))) ;;; Functions to control movement through synopsys code ;;; These functions over-ride the built-ins. ;;; (defun synopsys-beginning-of-statement (count) "Go to the beginning of the innermost synopsys statement. With prefix arg, go back N - 1 statements. If already at the beginning of a statement then go to the beginning of the preceding one. If within a comment, or next to a comment (only whitespace between), move by sentences instead of statements." (interactive "p") (let ((here (point)) (at-end-of-statement (if (not (bolp)) (save-excursion (skip-chars-backward " \t") (not (bolp)))))) ; if inside a comment, or looking at start of a comment (if (or (synopsys-in-comment-p) (looking-at comment-start-with-delimiters-re) (save-excursion (skip-chars-backward " \t") (goto-char (- (point) 3)) (and (looking-at (concat "\\s-" comment-end-re)) (> count 0)))) (if (> count 0) (progn (re-search-backward comment-start-skip nil t) (skip-chars-forward " \t\n") (setq count (1- count))) (search-forward comment-end nil t) (setq count (1+ count))) (while (> count 0) (synopsys-beginning-of-statement-1) (setq count (1- count))) (while (< count 0) (synopsys-end-of-statement-1) (setq count (1+ count)))))) (defun synopsys-end-of-statement (count) "Go to the end of the innermost synopsys statement. With prefix arg, go forward N - 1 statements. Move forward to end of the next statement if already at end. If within a string or comment, move by sentences instead of statements." (interactive "p") (synopsys-beginning-of-statement (- count))) (defun synopsys-end-of-statement-1 () (skip-chars-forward " \t") (cond ((eolp) (skip-chars-forward " \t\n") (if (looking-at comment-start-re) (forward-comment 1) (synopsys-end-of-statement-1))) (t (let ((start (point))) (end-of-line) (synopsys-backward-to-noncomment start) (if (= (preceding-char) ?\\) (progn (forward-line 1) (synopsys-end-of-statement-1))))))) (defun synopsys-beginning-of-statement-1 () (skip-chars-backward " \t") (cond ((and (bolp) (not (bobp))) (skip-chars-backward " \t\n") (cond ((synopsys-in-comment-p) ; are we inside a comment? (re-search-backward comment-start-skip nil t) (skip-chars-forward " \t\n")) ((save-excursion ; checking for being on edge of ; comment (forward-char -3) (looking-at comment-end-with-delimiters-re)) (re-search-backward comment-start-skip nil t) (skip-chars-forward " \t\n")) (t (beginning-of-line) (if (save-excursion (forward-char -1) (if (= (preceding-char) ?\\) ; in the middle of a ; backslashed line t)) (synopsys-beginning-of-statement-1)) (skip-chars-forward " \t")))) (t (beginning-of-line) (if (save-excursion (forward-char -1) (if (= (preceding-char) ?\\) ; in the middle of a ; backslashed line t)) (synopsys-beginning-of-statement-1)) (skip-chars-forward " \t")))) ;; Idea of ENDPOS is, indent each line, stopping when ;; ENDPOS is encountered. But it's too much of a pain to make that work. (defun indent-synopsys-exp (&optional endpos) "Indent each line of the synopsys grouping following point." (interactive) (let* ((indent-stack (list nil)) (opoint (point)) ;; May be altered below. (contain-stack (list (if endpos (let (funbeg) ;; Find previous fcn-start. (save-excursion (forward-char 1) (beginning-of-defun) (setq funbeg (point))) (setq opoint funbeg) ;; Try to find containing open, ;; but don't scan past that fcn-start. (save-restriction (narrow-to-region funbeg (point)) (condition-case nil (save-excursion (backward-up-list 1) (point)) ;; We gave up: must be between fcns. ;; Set opoint to beg of prev fcn ;; since otherwise calculate-synopsys-indent ;; will get wrong answers. (error (setq opoint funbeg) (point))))) (point)))) (case-fold-search nil) restart outer-loop-done inner-loop-done state ostate this-indent last-sexp at-else at-brace at-while last-depth this-point (next-depth 0)) ;; If the braces don't match, get an error right away. (save-excursion (forward-sexp 1)) ;; Realign the comment on the first line, even though we don't reindent it. (save-excursion (let ((beg (point))) (and (re-search-forward comment-start-skip (save-excursion (end-of-line) (point)) t) ;; Make sure this isn't a comment alone on a line ;; (which should be indented like code instead). (save-excursion (goto-char (match-beginning 0)) (skip-chars-backward " \t") (not (bolp))) ;; Make sure the comment starter we found ;; is not actually in a string or quoted. (let ((new-state (synopsys-parse-partial-sexp beg (point) nil nil state))) (and (not (nth 3 new-state)) (not (nth 5 new-state)))) (progn (indent-for-comment) (beginning-of-line))))) (save-excursion (setq outer-loop-done nil) (while (and (not (eobp)) (if endpos (< (point) endpos) (not outer-loop-done))) (setq last-depth next-depth) ;; Compute how depth changes over this line ;; plus enough other lines to get to one that ;; does not end inside a comment or string. ;; Meanwhile, do appropriate indentation on comment lines. (setq inner-loop-done nil) (while (and (not inner-loop-done) (not (and (eobp) (setq outer-loop-done t)))) (setq ostate state) (setq state (synopsys-parse-partial-sexp (point) (progn (end-of-line) (point)) nil nil state)) (setq next-depth (car state)) (if (and (car (cdr (cdr state))) (>= (car (cdr (cdr state))) 0)) (setq last-sexp (car (cdr (cdr state))))) ;; If this line started within a comment, indent it as such. (if (nth 4 ostate) (synopsys-indent-line)) ;; If it ends outside of comments or strings, exit the inner loop. ;; Otherwise move on to next line. (if (or (nth 3 state) (nth 4 state)) (forward-line 1) (setq inner-loop-done t))) (and endpos (while (< next-depth 0) (setq indent-stack (append indent-stack (list nil))) (setq contain-stack (append contain-stack (list nil))) (setq next-depth (1+ next-depth)) (setq last-depth (1+ last-depth)) (setcar (nthcdr 6 state) (1+ (nth 6 state))))) (setq outer-loop-done (and (not endpos) (<= next-depth 0))) (if outer-loop-done nil ;; If this line had ..))) (((.. in it, pop out of the levels ;; that ended anywhere in this line, even if the final depth ;; doesn't indicate that they ended. (while (> last-depth (nth 6 state)) (setq indent-stack (cdr indent-stack) contain-stack (cdr contain-stack) last-depth (1- last-depth))) (if (/= last-depth next-depth) (setq last-sexp nil)) ;; Add levels for any parens that were started in this line. (while (< last-depth next-depth) (setq indent-stack (cons nil indent-stack) contain-stack (cons nil contain-stack) last-depth (1+ last-depth))) (if (null (car contain-stack)) (setcar contain-stack (or (car (cdr state)) (save-excursion (forward-sexp -1) (point))))) (forward-line 1) (skip-chars-forward " \t") ;; Don't really reindent if the line is just whitespace, ;; or if it is past the endpos. ;; (The exit test in the outer while ;; does not exit until we have passed the first line ;; past the region.) (if (or (eolp) (and endpos (>= (point) endpos))) nil ;; Is this line in a new nesting level? ;; In other words, is this the first line that ;; starts in the new level? (if (and (car indent-stack) (>= (car indent-stack) 0)) nil ;; Yes. ;; Compute the standard indent for this level. (let (val) (if (= (char-after (car contain-stack)) ?{) (save-excursion (goto-char (car contain-stack)) (setq val (calculate-synopsys-indent-after-brace))) (setq val (calculate-synopsys-indent (if (car indent-stack) (- (car indent-stack)) opoint)))) ;; t means we are in a block comment and should ;; calculate accordingly. (if (eq val t) (setq val (calculate-synopsys-indent-within-comment))) (setcar indent-stack val))) ;; Adjust indent of this individual line ;; based on its predecessor. ;; Handle continuation lines, if, else, while, and so on. (if (/= (char-after (car contain-stack)) ?{) (setq this-indent (car indent-stack)) ;; Line is at statement level. ;; Is it a new statement? Is it an else? ;; Find last non-comment character before this line (save-excursion (setq this-point (point)) (setq at-else (and (looking-at "else\\b") (not (looking-at "else\\s_")))) (setq at-brace (= (following-char) ?{)) (setq at-while (and (looking-at "while\\b") (not (looking-at "while\\s_")))) (if (= (following-char) ?}) (setq this-indent (car indent-stack)) (synopsys-backward-to-noncomment opoint) (if (memq (preceding-char) '(0 ?\\)) ;; Preceding line has a continuation backslash, so ;; indent this line ;; synopsys-continued-statement-offset more than ;; the previous line. (progn (synopsys-backward-to-start-of-backslashed-exp (car contain-stack)) (setq this-indent (+ synopsys-continued-statement-offset (current-column) (if at-brace synopsys-continued-brace-offset 0)))) ;; Preceding line was a self-contained statement, so ;; use the standard indent for this level. (cond (at-else (progn (synopsys-backward-to-start-of-if opoint) (setq this-indent (current-indentation)))) ((eq (preceding-char) ?\,) (goto-char this-point) (setq this-indent (calculate-synopsys-indent))) (t (setq this-indent (car indent-stack)))))))) ;; Adjust line indentation according to its contents (if (= (following-char) ?}) (setq this-indent (- this-indent synopsys-indent-level))) (if (= (following-char) ?{) ;; Don't move an open-brace in column 0. (if (zerop (current-column)) (setq this-indent 0) (setq this-indent (+ this-indent synopsys-brace-offset)))) ;; Don't leave indentation in empty lines. (if (eolp) (setq this-indent 0)) ;; Put chosen indentation into effect. (= (current-column) this-indent) (progn (delete-region (point) (progn (beginning-of-line) (point))) (indent-to this-indent))) ;; Indent any comment following the text. (or (looking-at comment-start-skip) (save-excursion (let ((beg (point))) (and (re-search-forward comment-start-skip (save-excursion (end-of-line) (point)) t) ;; Make sure the comment starter we found ;; is not actually in a string or quoted. (let ((new-state (synopsys-parse-partial-sexp beg (point) nil nil state))) (and (not (nth 3 new-state)) (not (nth 5 new-state)))) (indent-for-comment)))))))))) ;; Indent every line whose first char is between START and END inclusive. (defun synopsys-indent-region (start end) (save-excursion (goto-char start) ;; Advance to first nonblank line. (skip-chars-forward " \t\n") (beginning-of-line) (let ((endmark (copy-marker end)) (synopsys-tab-always-indent t)) (while (and (bolp) (not (eobp)) (< (point) endmark)) ;; Indent one line as with TAB. (let ((shift-amt (synopsys-indent-line)) nextline sexpbeg sexpend) (save-excursion ;; Find beginning of following line. (save-excursion (forward-line 1) (setq nextline (point))) ;; Find first beginning-of-sexp for sexp extending past ;; this line. (beginning-of-line) (while (< (point) nextline) (condition-case nil (progn (forward-sexp 1) (setq sexpend (point-marker))) (error (setq sexpend nil) (goto-char nextline))) (skip-chars-forward " \t\n")) (if sexpend (progn ;; Make sure the sexp we found really starts on the ;; current line and extends past it. (goto-char sexpend) (backward-sexp 1) (setq sexpbeg (point))))) ;; If that sexp ends within the region, ;; indent it all at once, fast. (if (and sexpend (> sexpend nextline) (<= sexpend endmark) (< sexpbeg nextline)) (progn (indent-synopsys-exp) (goto-char sexpend))) ;; Move to following line and try again. (and sexpend (set-marker sexpend nil)) (forward-line 1))) (set-marker endmark nil)))) (defun set-synopsys-style (style &optional global) "Set synopsys-mode variables to use one of several different indentation styles. The arguments are a string representing the desired style and a flag which, if non-nil, means to set the style globally. \(Interactively, the flag comes from the prefix argument.) Available styles are GNU, K&R, BSD and Whitesmith." (interactive (list (let ((completion-ignore-case t)) (completing-read "Use which synopsys indentation style? " synopsys-style-alist nil t)) current-prefix-arg)) (let ((vars (cdr (assoc style synopsys-style-alist)))) (or vars (error "Invalid synopsys indentation style `%s'" style)) (while vars (or global (make-local-variable (car (car vars)))) (set (car (car vars)) (cdr (car vars))) (setq vars (cdr vars))))) ;;; This page handles insertion and removal of backslashes (defun synopsys-backslash-region (from to delete-flag) "Insert, or delete the continuation backslash on the lines in the region. This function examines each line in the region, checking to see if the line is longer than the `fill-column'. If so, it chops the line at the appropriate place and adds a continuation backslash. If an argument is given to the command, backslashed lines are joined into 1 long line, regardless of the `fill-column' setting." (interactive "r\nP") (save-excursion (goto-char from) (while (< (point) to) (if delete-flag (synopsys-unslash-it) (synopsys-slash-it)) (forward-line 1) ))) (defun synopsys-unslash-it () "This function re-joins lines that have been split by a continuation backslash." (synopsys-backward-to-start-of-backslashed-exp) (end-of-line) (if (eq (preceding-char) ?\\) (progn (delete-char -1) (delete-indentation t) (synopsys-unslash-it)))) ;;; This page handles the custom parsing for synopsys mode ;;; (defun synopsys-parse-partial-sexp (beg end &optional target-depth stop-before start-state stop-comment) "A function which mimics the standard Elisp parse-partial-sexp, except that this function can properly handle the weird cases that synopsys code can generate. In particular, handling comments is quite different than other languages: comment markers are also used for specifying path names, so you need special care in identifying a comment." (or target-depth (setq target-depth -10)) (let* ((brace-count 0) (string-count 0) (min-depth 0) inside-comment endpoint flag syn-last-sexp (syn-state (list 0 nil nil nil nil nil 0 nil)) nested-sexp-point target-reached nested-point-list) ;; if a previous state is being passed in, use it (if start-state (progn (setq brace-count (nth 0 start-state)) (setq nested-sexp-point (nth 1 start-state)) (setq syn-last-sexp (nth 2 start-state)) (if (nth 3 start-state) (setq string-count 1) (setq string-count 0)) (setq inside-comment (nth 4 start-state)) (setq min-depth brace-count) (setq syn-state start-state))) (setq nested-point-list (cons nested-sexp-point ())) ;; goto start of the region we're going to parse (goto-char beg) ;; set the ending point to be the beginning, this will change as we parse (setq endpoint beg) ;; ;; while still not at end of the region so loop (while (< (point) end) (cond ((and stop-comment inside-comment) ;; found a comment, and user requested we stop when we find ;; a comment, so goto the end of the region to force us out ;; of the while loop (setq endpoint (point)) (goto-char end)) (target-reached ;; requested depth of parenthesis has been reached, so stop ;; looping by going to the end of the region. (setq endpoint (point)) (goto-char end)) (t ;; haven't reached anything that will force us to stop ;; parsing, so let's examine what we're looking at. Search ;; for strings, comments, and parentheses. (cond ((= string-count 1) ;; started a string, so look for the end of it (setq flag (re-search-forward "\\s\"" end t))) (inside-comment ;; inside a comment, so look for the end of it (setq flag (re-search-forward comment-end-with-delimiters-re end t))) (t ;; not inside a comment or string, so look for either ;; string start, a comment start, or an open or ;; closed paren (setq flag (re-search-forward (concat "\\s\"\\|\\s(\\|\\s)\\|" comment-start-re ) end t)) )) ;; if found a match, go to the beginning of the match-string (if (and (match-beginning 0) flag) (goto-char (match-beginning 0))) (cond ((not flag) nil) ((> (point) end) nil) ((looking-at "\"") ;; if we've found a quote, ensure its not escaped (if (not (= (preceding-char) ?\\)) (if (= string-count 1) (setq string-count 0) (setq string-count 1)))) ((looking-at "(") (setq nested-point-list (cons nested-sexp-point nested-point-list)) (setq nested-sexp-point (point)) (setq brace-count (+ brace-count 1))) ((looking-at "{") (setq nested-point-list (cons nested-sexp-point nested-point-list)) (setq nested-sexp-point (point)) (setq brace-count (+ brace-count 1))) ((looking-at ")") (if (> brace-count 0 ) (progn (setq nested-sexp-point (car nested-point-list)) (setq nested-point-list (cdr nested-point-list)) (setq brace-count (- brace-count 1)) (if (= brace-count target-depth) (setq target-reached t)) (if (< brace-count min-depth) (setq min-depth brace-count))) (error "Round brace count mismatch"))) ((looking-at "}") (if (> brace-count 0) (progn (setq nested-sexp-point (car nested-point-list)) (setq nested-point-list (cdr nested-point-list)) (setq brace-count (- brace-count 1)) (if (= brace-count target-depth) (setq target-reached t)) (if (< brace-count min-depth) (setq min-depth brace-count))) (error "Curly brace count mismatch"))) (t (skip-chars-forward " \t\n") (cond ((looking-at comment-start-re) ;; if we are at the beginning of the line, we ;; know that we've found a real comment ;; start, if not we should check the ;; character before the comment start and see ;; what character class it belongs to. If it ;; belongs to character class 32 (a space), ;; the character is whitespace and we've ;; found a real comment start. If its part of ;; another class, its definitely not a ;; comment. (if (not (bolp)) ;; if the (if (= (char-syntax (preceding-char)) 32) (setq inside-comment t)) (setq inside-comment t))) ((looking-at comment-end-re) (if inside-comment (setq inside-comment nil) (error "Comment count mismatch"))) )) ) (forward-char 1) (setq endpoint (point)) (condition-case nil (save-excursion (forward-sexp -1) (setq syn-last-sexp (point))) (error (setq syn-last-sexp nil))) (setq syn-state (list brace-count nested-sexp-point syn-last-sexp (if (= string-count 0) nil string-count) inside-comment nil min-depth nil)) ) ) ) (if (> endpoint end) (goto-char end) (goto-char endpoint)) syn-state ) ) ;;; This page handles the font-lock functions ;;; ;;; extra font-lock customization - needed because regular font-lock ;;; gets confused with the comments in synopsys mode. This version, ;;; based on the font-lock-fontify-syntactically-region function, called ;;; synopsys-parse-partial-sexp which properly fontifies synopsys code. ;; These record the parse state at a particular position, always the start of a ;; line. Used to make `synopsys-font-lock-fontify-syntactically-region' faster. (defvar syn-font-lock-cache-position nil) (defvar syn-font-lock-cache-state nil) (make-variable-buffer-local 'syn-font-lock-cache-position) (make-variable-buffer-local 'syn-font-lock-cache-state) (defun synopsys-font-lock-fontify-region (beg end loudly) "This function is completely based on \\[font-lock-fontify-region] in the font-lock package, except that it called a custom version of font-fy-syntactically-region." (let ((modified (buffer-modified-p)) (buffer-undo-list t) (inhibit-read-only t) (old-syntax-table (syntax-table)) before-change-functions after-change-functions buffer-file-name buffer-file-truename) (unwind-protect (save-restriction (widen) ;; Use the fontification syntax table, if any. (if font-lock-syntax-table (set-syntax-table font-lock-syntax-table)) ;; Now do the fontification. (if font-lock-keywords-only (font-lock-unfontify-region beg end) ; originally ... ; (font-lock-fontify-syntactically-region beg end loudly)) ; now .... (synopsys-font-lock-fontify-syntactically-region beg end loudly)) (font-lock-fontify-keywords-region beg end loudly)) ;; Clean up. (set-syntax-table old-syntax-table) (and (not modified) (buffer-modified-p) (set-buffer-modified-p nil))) )) (defun synopsys-font-lock-fontify-syntactically-region (start end &optional loudly) "Put proper face on each string and comment between START and END. START should be at the beginning of a line. This function is based on the standard font-lock package. It was modified to use \\[synopsys-parse-partial-sexp], and a few other small changes made." (let ((synstart (concat "\\s\"\\|" comment-start-re )) (comstart (concat "\\s<\\|" comment-start-re )) state prev prevstate) (if loudly (message "Fontifying %s... (syntactically...)" (buffer-name))) (goto-char start) ;; ;; Find the state at the `beginning-of-line' before `start'. (if (eq start syn-font-lock-cache-position) ;; Use the cache for the state of `start'. (setq state syn-font-lock-cache-state) ;; Find the state of `start'. (if (null font-lock-beginning-of-syntax-function) ;; Use the state at the previous cache position, if any, or ;; otherwise calculate from `point-min'. (if (or (null syn-font-lock-cache-position) (< start syn-font-lock-cache-position)) (setq state (synopsys-parse-partial-sexp (point-min) start)) (setq state (synopsys-parse-partial-sexp syn-font-lock-cache-position start nil nil syn-font-lock-cache-state))) ;; Call the function to move outside any syntactic block. (funcall font-lock-beginning-of-syntax-function) (setq state (synopsys-parse-partial-sexp (point) start))) ;; Cache the state and position of `start'. (setq syn-font-lock-cache-state state syn-font-lock-cache-position start)) ;; ;; If the region starts inside a string, show the extent of it. (if (nth 3 state) (let ((beg (point))) (while (and (re-search-forward "\\s\"" end 'move) (nth 3 (synopsys-parse-partial-sexp beg (point) nil nil state)))) (put-text-property beg (point) 'face font-lock-string-face) (setq state (synopsys-parse-partial-sexp beg (point) nil nil state)))) ;; ;; Likewise for a comment. (if (nth 4 state) (let ((beg (point))) (save-restriction (narrow-to-region (point-min) end) (condition-case nil (progn (re-search-backward comstart (point-min) 'move) (forward-comment 1) ;; forward-comment skips all whitespace, ;; so go back to the real end of the comment. (skip-chars-backward " \t")) (error (goto-char end)))) (put-text-property beg (point) 'face font-lock-comment-face) (setq state (synopsys-parse-partial-sexp beg (point) nil nil state)))) ;; ;; Find each interesting place between here and `end'. (while (and (< (point) end) (setq prev (point) prevstate state) (re-search-forward synstart end t) (progn ;; Clear out the fonts of what we skip over. (remove-text-properties prev (point) '(face nil)) ;; Verify the state at that place ;; so we don't get fooled by \" or \;. (setq state (synopsys-parse-partial-sexp prev (point) nil nil state)))) (let ((here (point))) (if (nth 4 state) ;; ;; We found a real comment start. (let ((beg (or (match-end 1) (match-beginning 0)))) (goto-char beg) (save-restriction (narrow-to-region (point-min) end) (condition-case nil (progn (forward-comment 1) ;; forward-comment skips all whitespace, ;; so go back to the real end of the comment. (skip-chars-backward " \t")) (error (goto-char end)))) (put-text-property beg (point) 'face font-lock-comment-face) (setq state (synopsys-parse-partial-sexp here (point) nil nil state))) (if (nth 3 state) ;; ;; We found a real string start. (let ((beg (or (match-end 1) (match-beginning 0)))) (while (and (re-search-forward "\\s\"" end 'move) (nth 3 (synopsys-parse-partial-sexp here (point) nil nil state)))) (put-text-property beg (point) 'face font-lock-string-face) (setq state (synopsys-parse-partial-sexp here (point) nil nil state)))))) ;; ;; Make sure `prev' is non-nil after the loop ;; only if it was set on the very last iteration. (setq prev nil)) ;; ;; Clean up. (and prev (remove-text-properties prev end '(face nil))))) (defun synopsys-submit-bug-report () "Submit a bug report on synopsys-mode via mail." (interactive) ;; load in reporter (and (y-or-n-p "Do you want to submit a report on synopsys-mode? ") (require 'reporter) (reporter-submit-bug-report "harts@nortel.ca" (concat "synopsys-mode " synopsys-mode-version) (list ;; report the variables that might be of interest 'tab-width 'fill-column 'synopsys-indent-level 'synopsys-brace-offset 'synopsys-continued-statement-offset 'synopsys-continued-brace-offset 'synopsys-auto-indent 'synopsys-auto-cformat 'synopsys-auto-backslash 'synopsys-comment-style 'synopsys-font-lock-highlight-level ) nil nil "Submitting a bug report (be sure to include an example):" ))) ;; provide ourself (provide 'synopsys-mode) ;;; synopsys-mode.el ends here