****Solution to Issue 1 by Stephan - see Answer below****
I mark \ as an escape character in the syntax table, but then override that designation for the Mathematica syntax elements like \[Infinity]. Here is my syntax-propertize-function:
(defconst math-syntax-propertize-function
(syntax-propertize-rules
("\\\\\\[\\([A-Z][A-Za-z]*\\)]" (0 "_"))))
I referenced it from the (defun math-node() function like so:
(set (make-local-variable 'syntax-propertize-function)
math-syntax-propertize-function)
In my first attempt, I didn't use the make-local-variable function and I was surprised when my elisp buffer highlighting went awry.
****End Solution to Issue 1****
I am implementing a major-mode in Emacs derived from cc-mode for editing Mathematica files. The goal is syntax highlighting and indentation. I will leave interfacing with the Mathematica kernel for later.
I have the basic functionality working, but there are a couple of sticking points that are giving me trouble.
****Issue 1** - The \ character is used as an escape character and to prefix multi-character, bracketed keywords. **
Like many languages, Mathematica uses the \ character to escape " and other \ characters is strings.
Mathematic has what are called in Mathematica speak Syntax Characters like \[Times], \[Element], \[Infinity], etc. that represent mathematica operators and constants.
And, Mathematica makes heavy use of [ and ] instead of ( and ) for function definitions and calls, etc.
So, if I mark \ as an escape character in the syntax-table, then my brackets become mis-matched anywhere I use a Syntax Character. E.g.,
If[x < \[Pi], True, False]
Of course, cc-mode is intent on ignoring the [ right after the \. Given the functional nature of Mathematica, the mode is almost useless if it cannot match brackets. Think lisp without paren matching.
If I don't put \ in the syntax-table as an escape character, then how do I handle escape sequences in comments and strings?
It would be great if I could put Times, Element, Infinity, etc in a keyword list and have everything work correctly.
****Issue 2** - The syntax of Mathematica is different enough from C,C++,Java,ObjC, etc. that cc-mode's builtin syntactical analysis doesn't always produce the desired result.**
Consider the following code block:
FooBar[expression1,
expression2,
expression3];
This formats beautifully because the expressions are recognized as an argument list.
However, if a list is passed as an argument,
FooBar[{expression1,
expression2,
expression3}];
the result is not pretty because the expressions are considered continuations of a single statement within the { and }. Unfortunately, the simple hack of setting c-continuation-offset to 0 breaks actual continuations like,
addMe[x_Real, y_Real] :=
Plus[x, y];
which you want to be indented.
The issue is that in Mathematica { and } delineate lists and not code blocks.
Here is the current elisp file I am using:
(require 'cc-mode)
;; There are required at compile time to get the sources for the
;; language constants.
(eval-when-compile
(require 'cc-langs)
(require 'cc-fonts))
;; Add math mode the the language constant system. This needs to be
;; done at compile time because that is when the language constants
;; are evaluated.
(eval-and-compile
(c-add-language 'math-mode 'c-mode))
;; Function names
(c-lang-defconst c-cpp-matchers
math (append
(c-lang-const c-cpp-matchers c)
;; Abc[
'(("\\<\\([A-Z][A-Za-z0-9]*\\)\\>\\[" 1 font-lock-type-face))
;; abc[
'(("\\<\\([A-Za-z][A-Za-z0-9]*\\)\\>\\[" 1 font-lock-function-name-face))
;; Abc
'(("\\<\\([A-Z][A-Za-z0-9]*\\)\\>" 1 font-lock-keyword-face))
;; abc_
'(("\\<\\([a-z][A-Za-z0-9]*[_]\\)\\>" 1 font-lock-variable-name-face))
))
;; font-lock-comment-face
;; font-lock-doc-face
;; font-lock-string-face
;; font-lock-keyword-fact
;; font-lock-function-name-face
;; font-lock-constant-face
;; font-lock-type-face
;; font-lock-builtin-face
;; font-lock-reference-face
;; font-lock-warning-face
;; There is no line comment character.
(c-lang-defconst c-line-comment-starter
math nil)
;; The block comment starter is (*.
(c-lang-defconst c-block-comment-starter
math "(*")
;; The block comment ender is *).
(c-lang-defconst c-block-comment-ender
math "*)")
;; The assignment operators.
(c-lang-defconst c-assignment-operators
math '("=" ":=" "+=" "-=" "*=" "/=" "->" ":>"))
;; The operators.
(c-lang-defconst c-operators
math `(
;; Unary.
(prefix "+" "-" "!")
;; Multiplicative.
(left-assoc "*" "/")
;; Additive.
(left-assoc "+" "-")
;; Relational.
(left-assoc "<" ">" "<=" ">=")
;; Equality.
(left-assoc "==" "=!=")
;; Assignment.
(right-assoc ,#(c-lang-const c-assignment-operators))
;; Sequence.
(left-assoc ",")))
;; Syntax modifications necessary to recognize keywords with
;; punctuation characters.
;; (c-lang-defconst c-identifier-syntax-modifications
;; math (append '((?\\ . "w"))
;; (c-lang-const c-identifier-syntax-modifications)))
;; Constants.
(c-lang-defconst c-constant-kwds
math '( "False" "True" )) ;; "\\[Infinity]" "\\[Times]" "\\[Divide]" "\\[Sqrt]" "\\[Element]"\
))
(defcustom math-font-lock-extra-types nil
"Extra types to recognize in math mode.")
(defconst math-font-lock-keywords-1 (c-lang-const c-matchers-1 math)
"Minimal highlighting for math mode.")
(defconst math-font-lock-keywords-2 (c-lang-const c-matchers-2 math)
"Fast normal highlighting for math mode.")
(defconst math-font-lock-keywords-3 (c-lang-const c-matchers-3 math)
"Accurate normal highlighting for math mode.")
(defvar math-font-lock-keywords math-font-lock-keywords-3
"Default expressions to highlight in math mode.")
(defvar math-mode-syntax-table nil
"Syntax table used in math mode.")
(message "Setting math-mode-syntax-table to nil to force re-initialization")
(setq math-mode-syntax-table nil)
;; If a syntax table has not yet been set, allocate a new syntax table
;; and setup the entries.
(unless math-mode-syntax-table
(setq math-mode-syntax-table
(funcall (c-lang-const c-make-mode-syntax-table math)))
(message "Modifying the math-mode-syntax-table")
;; character (
;; ( - open paren class
;; ) - matching paren character
;; 1 - 1st character of comment delimitter (**)
;; n - nested comments allowed
(modify-syntax-entry ?\( "()1n" math-mode-syntax-table)
;; character )
;; ) - close parent class
;; ( - matching paren character
;; 4 - 4th character of comment delimitter (**)
;; n - nested comments allowed
(modify-syntax-entry ?\) ")(4n" math-mode-syntax-table)
;; character *
;; . - punctuation class
;; 2 - 2nd character of comment delimitter (**)
;; 3 - 3rd character of comment delimitter (**)
(modify-syntax-entry ?\* ". 23n" math-mode-syntax-table)
;; character [
;; ( - open paren class
;; ] - matching paren character
(modify-syntax-entry ?\[ "(]" math-mode-syntax-table)
;; character ]
;; ) - close paren class
;; [ - mathcing paren character
(modify-syntax-entry ?\] ")[" math-mode-syntax-table)
;; character {
;; ( - open paren class
;; } - matching paren character
(modify-syntax-entry ?\{ "(}" math-mode-syntax-table)
;; character }
;; ) - close paren class
;; { - matching paren character
(modify-syntax-entry ?\} "){" math-mode-syntax-table)
;; The following characters are punctuation (i.e. they cannot appear
;; in identifiers).
;;
;; / ' % & + - ^ < > = |
(modify-syntax-entry ?\/ "." math-mode-syntax-table)
(modify-syntax-entry ?\' "." math-mode-syntax-table)
(modify-syntax-entry ?% "." math-mode-syntax-table)
(modify-syntax-entry ?& "." math-mode-syntax-table)
(modify-syntax-entry ?+ "." math-mode-syntax-table)
(modify-syntax-entry ?- "." math-mode-syntax-table)
(modify-syntax-entry ?^ "." math-mode-syntax-table)
(modify-syntax-entry ?< "." math-mode-syntax-table)
(modify-syntax-entry ?= "." math-mode-syntax-table)
(modify-syntax-entry ?> "." math-mode-syntax-table)
(modify-syntax-entry ?| "." math-mode-syntax-table)
;; character $
;; _ - word class (since $ is allowed in identifier names)
(modify-syntax-entry ?\$ "_" math-mode-syntax-table)
;; character \
;; . - punctuation class (for now treat \ as punctuation
;; until we can fix the \[word] issue).
(modify-syntax-entry ?\\ "." math-mode-syntax-table)
) ;; end of math-mode-syntax-table adjustments
;;
;;
(defvar math-mode-abbrev-table nil
"Abbrevation table used in math mode buffers.")
(defvar math-mode-map (let ((map (c-make-inherited-keymap)))
map)
"Keymap used in math mode buffers.")
;; math-mode
;;
(defun math-mode ()
"Major mode for editing Mathematica code."
(interactive)
(kill-all-local-variables)
(c-initialize-cc-mode t)
(set-syntax-table math-mode-syntax-table)
(setq major-mode 'math-mode
mode-name "Math"
local-abbrev-table math-mode-abbrev-table
abbrev-mode t)
(use-local-map math-mode-map)
(c-init-language-vars math-mode)
(c-common-init 'math-mode)
(run-hooks 'c-mode-common-hook)
(run-hooks 'math-mode-hook)
(c-update-modeline))
(provide 'math-mode)
And a screenshot of some .
While cc-mode is designed to be adaptable to various languages, I'm not sure it will serve you well for Mathematica, because the syntax is too far from the one well-supported by cc-mode. I would suggest to try SMIE (an indentation engine that appeared in Emacs-23.4 and that was originally built for SML but is currently used for a variety of languages). Just like cc-mode, SMIE is not ideal for all languages either, but I wouldn't be surprised if it works better than cc-mode in your case.
For the backslash issue, your best bet is to use syntax-propertize-function to change the escaping-nature of specific backslashes (either set \ as escaping in the syntax-table and then mark the \ of \[foo] as non-escaping, or leave the \ as non-escaping in the syntax-table and then mark those \ of \" and \\ as escaping).
Related
I'm trying to set up syntax colouring for Imp, an Algol-like language that uses keyword stropping, i.e. a keyword is the '%' character followed by alphabetics up to any non-alpha, such as %begin. I found that modify-syntax-entry was sufficient to colour Imp comments, but I had to use Hi-lock to colour keywords. What I'ld like help with is: how can I load the regexps for hi-lock from my ~/.emacs file when opening any file with a .imp extension, rather than having to explicitly save the rules in every individual .imp file? Here's what I have so far:
(defconst my-imp-mode-syntax-table
(let ((table (make-syntax-table)))
(modify-syntax-entry ?' "\"" table)
(modify-syntax-entry ?\" "\"" table)
(modify-syntax-entry ?! "<" table)
(modify-syntax-entry ?\n ">" table)
(modify-syntax-entry ?{ "<" table)
(modify-syntax-entry ?} ">" table)
(modify-syntax-entry ?\( "()" table)
(modify-syntax-entry ?\) ")(" table)
table))
(define-derived-mode my-imp-mode prog-mode "Simple Imp Mode"
:syntax-table my-imp-mode-syntax-table
(font-lock-fontify-buffer))
(add-to-list 'auto-mode-alist '("\\.i\\'" . my-imp-mode))
(add-to-list 'auto-mode-alist '("\\.imp\\'" . my-imp-mode))
(global-hi-lock-mode 1)
(setq hi-lock-file-patterns-policy (lambda (pattern) t))
(defface imp-keyword
'((t (:weight bold :foreground "cyan")))
"Face for IMP keywords"
:group 'hi-lock-faces)
(defface imp-constant
'((t (:foreground "green")))
"Face for IMP numeric constants"
:group 'hi-lock-faces)
;; I would like to load these patterns on opening a .imp file:
;; (("\\%[A-Za-z]*" (0 (quote imp-keyword) prepend)))
;; (("\\<[\\-+]*[0-9]*\\.?[0-9]+\\(\\|#[\\-+]?[0-9]+\\)?\\>" (0 (quote imp-constant) prepend)))
Here is an example of an Imp file:
! Hi-lock: (("\\%[A-Za-z]*" (0 (quote imp-keyword) prepend)))
! Hi-lock: (("\\<[\\-]?[0-9]*\\.?[0-9]+\\(\\#[\\-+]?[0-9]+\\)?\\>" (0 (quote imp-constant) prepend)))
%begin
! ackerman function - this is a whole-line comment
%integer x,y,j,k
%integerfn acker {short for ackerman - this is a bracketed comment by the way} (%integer m,n)
%if m = 0 %then %result = n+1
%if n = 0 %then %result = acker(m-1,1)
%result = acker(m-1, acker(m, n-1))
%end
prompt("Ackerman, First param (1..4)?"); read(x)
prompt(" Second param (1..7)?"); read(y)
write(acker(x,y), 4); newline
%endofprogram
You can see what the expected highlighting looks like by applying the elisp from above. (The details of the colouring are just a draft until I work out how to do it. I can tweak the colours etc later)
The Hi-lock module was not required - it is possible to write syntax colouring for a new language using the standard syntax colouring mechanism, as follows:
(defconst imp-mode-syntax-table
(let ((table (make-syntax-table)))
;; turn off ' and " from being string delimiters
(modify-syntax-entry ?' "-" table)
(modify-syntax-entry ?\" "-" table)
table))
;; Highlight comments, %stropped keywords, and numbers:
(setq imp-highlights
'(
;; many forms of comments including after labels
(";[ ]*!" ".*" nil nil (0 font-lock-comment-face))
("^[ ]*!" ".*;" nil nil (0 font-lock-comment-face))
("^[ ]*!" ".*" nil nil (0 font-lock-comment-face))
("%c\\([ ]+[%]+\\|[%]*\\)*o\\([ ]+[%]+\\|[%]*\\)*m\\([ ]+[%]+\\|[%]*\\)*m\\([ ]+[%]+\\|[%]*\\)*e\\([ ]+[%]+\\|[%]*\\)*n\\([ ]+[%]+\\|[%]*\\)*t" ".*;" nil nil
(0 font-lock-comment-face))
("%c\\([ ]+[%]+\\|[%]*\\)*o\\([ ]+[%]+\\|[%]*\\)*m\\([ ]+[%]+\\|[%]*\\)*m\\([ ]+[%]+\\|[%]*\\)*e\\([ ]+[%]+\\|[%]*\\)*n\\([ ]+[%]+\\|[%]*\\)*t" "[^$]*" nil nil
(0 font-lock-comment-face))
(":[ ]*!" "[^$]*" nil nil (0 font-lock-comment-face))
("{[^}]*}" . 'font-lock-comment-face )
("{.*$" . 'font-lock-comment-face )
;; char constants, old-style strings, and old-style based constants
("[MBOXER]?'[^']*'" . 'font-lock-constant-face)
("\"[^\"]*\"" . 'font-lock-string-face )
;; Based IMP constants
("\\<[0-9][ ]*[0-9 ]*[ ]*_[ ]*[0-9A-Fa-f][0-9A-Fa-f ]*\\>" . 'font-lock-constant-face)
;; Decimal IMP constants
("\\<[0-9][0-9 ]*\\.[ ]*[0-9][0-9 ]*#[ ]*[-+]?[ ]*[0-9][0-9 ]*\\>" . 'font-lock-constant-face)
("\\<[0-9][0-9 ]*\\.[ ]*[0-9][0-9 ]*\\>" . 'font-lock-constant-face)
;; Integer IMP constants
("\\<[0-9][ ]*[0-9][0-9 ]*\\>" . 'font-lock-constant-face)
("\\<[0-9][ ]*\\>" . 'font-lock-constant-face)
;; stropped keywords
("\\%[A-Za-z][A-Za-z]*" . 'font-lock-keyword-face )
))
(define-derived-mode imp-mode prog-mode "Simple Imp Mode"
:syntax-table imp-mode-syntax-table
(setq font-lock-defaults '(imp-highlights))
(font-lock-fontify-buffer)
)
;; Apply automatically to Imp source files:
(add-to-list 'auto-mode-alist '("\\.i\\'" . imp-mode))
(add-to-list 'auto-mode-alist '("\\.imp\\'" . imp-mode))
(add-to-list 'auto-mode-alist '("\\.imp77\\'" . imp-mode))
(add-to-list 'auto-mode-alist '("\\.imp80\\'" . imp-mode))
;; enter <esc>xfun<cr> to disable imp-mode if unwanted during an edit.
Based on the info from http://xahlee.info/emacs/emacs/elisp_syntax_coloring.html
I'm writing a major mode where I can have multiline strings like this:
Text : >abcde
fgh
ijklmonp<
where '>' and '<' indicate the respective start and end of the string. The following syntax table entries only mark >...> and <...< strings, which is not what I want.
(modify-syntax-entry ?> "\"" st)
(modify-syntax-entry ?< "\"" st)
Currently the best solution is using generic string delimiters: ‘|’, but it still messes up my system as I have >...<...< situations sometimes. The best would be if I could use a multiline regexp like
^Text : >.*<$
How can I achieve this?
As thornjad explains, this is not supported directly by syntax-table, so you need to use syntax-propertize-function. E.g.
(defconst my-syntax-propertize
(syntax-propertize-rules
(">" (0 (unless (nth 8 (save-excursion (syntax-ppss (match-beginning 0)))
(string-to-syntax "|"))))
("<" (0 (when (eq t (nth 3 (save-excursion
(syntax-ppss (match-beginning 0))))
(string-to-syntax "|"))))))
then in your major mode function:
(setq-local syntax-propertize-function my-syntax-propertize)
The nth 8 test makes sure > is only marked as a string delimiter if it is not within another string or comment, and the nth 3 test makes sure that < is only marked as a string delimiter when it occurs with a string that was started by another generic string delimiter.
Unfortunately modify-syntax-entry isn't powerful enough to handle this sort of situation. Luckily we have other options! My orson-mode deals with a similar issue where strings are delimited by double-single quotes ('') instead of double quotes (").
To do this, a regexp looks for the entire string, quotes included, then uses Emacs's string-fence class to mark the quotes as fences.
(defconst orson--string-rx
"\\(''[^']*''\\)")
(defun orson-syntax-propertize-function (start end)
(save-excursion
(goto-char start)
(while (re-search-forward orson--string-rx end 'noerror)
(let ((a (match-beginning 1))
(b (match-end 1))
(string-fence (string-to-syntax "|")))
(put-text-property a (1+ a) 'syntax-table string-fence)
(put-text-property (1- b) b 'syntax-table string-fence))))
I'm trying to setup an emacs major-mode which essentially just highlights text between lots of different characters, in different colors. I have square brackets working with:
(font-lock-add-keywords nil '(("\\[\\(.*\\)\\]"
1 font-lock-keyword-face prepend)))
but when I try replacing the [ and ] with other characters, it stops working. For example, round parentheses '()' does not work:
(font-lock-add-keywords nil '(("\\(\\(.*\\)\\)"
1 font-lock-function-name-face prepend)))
Trying single, double, or back-quotes, etc also don't work. I'm completely unfamiliar with lisp-syntax --- what am I doing wrong? Also: is there any way to include the characters bracketing the expression?
You're mixing regular expressions and regular strings.
Try these:
;; square brackets - escape the first one so you don't get a [..] regexp
(font-lock-add-keywords nil '(("\\(\\[.*]\\)"
1 font-lock-keyword-face prepend)))
;; parentheses - don't escape the parentheses you want to match!
(font-lock-add-keywords nil '(("\\((.*)\\)"
1 font-lock-keyword-face prepend)))
;; quotes - single escape so you don't break your string:
(font-lock-add-keywords nil '(("\\(\".*\"\\)"
1 font-lock-keyword-face prepend)))
;; other characters - not regexps, so don't escape them:
(font-lock-add-keywords nil '(("\\('.*'\\)"
1 font-lock-keyword-face prepend)))
(font-lock-add-keywords nil '(("\\(<.*>\\)"
1 font-lock-keyword-face prepend)))
There are Tags as in #+AUTHOR or #+LATEX in org-mode - are they called tags? I'd like to define my own tag which calls a function to preprocess the data and then outputs it - if the export target is LaTeX.
My solution was defining an own language, qtree, for SRC blocks.
#+BEGIN_SRC qtree
[.CP [.TP [.NP [] [.N' [.N Syntax] []]] [.VP [] [.V' [.V sucks] []]]]]
#+END_SRC
And process it accordingly. I even added a qtree-mode with paredit.
And a landscape parameter if the trees grow big. https://github.com/Tass/emacs-starter-kit/blob/master/vendor/assorted/org-babel-qtree.el
(require 'org)
(defun org-babel-execute:qtree (body params)
"Reformat a block of lisp-edited tree to one tikz-qtree likes."
(let (( tree
(concat "\\begin{tikzpicture}
\\tikzset{every tree node/.style={align=center, anchor=north}}
\\Tree "
(replace-regexp-in-string
" \\_<\\w+\\_>" (lambda (x) (concat "\\\\\\\\" (substring x 1)))
(replace-regexp-in-string
(regexp-quote "]") " ]" ; qtree needs a space
; before every closing
; bracket.
(replace-regexp-in-string
(regexp-quote "[]") "[.{}]" body)) ; empty leaf
; nodes, see
; http://tex.stackexchange.com/questions/75915
) ; For
; http://tex.stackexchange.com/questions/75217
"\n\\end{tikzpicture}"
)))
(if (assoc :landscape params)
(concat "\\begin{landscape}\n" tree "\n\\end{landscape}")
tree)))
(setq org-babel-default-header-args:qtree '((:results . "latex") (:exports . "results")))
(add-to-list 'org-src-lang-modes '("qtree" . qtree))
(define-generic-mode
'qtree-mode ;; name of the mode to create
'("%") ;; comments start with '%'
'() ;; no keywords
'(("[." . 'font-lock-operator) ;; some operators
("]" . 'font-lock-operator))
'() ;; files for which to activate this mode
'(paredit-mode) ;; other functions to call
"A mode for qtree edits" ;; doc string for this mode
)
They seem to be called keywords for in-buffer settings no more. Whatever they're called, they don't seem to be user-definable.
What you want to do is extremely related to a common way of handling whereas to export with xelatex or pdflatex as described on Worg.
The relevant part would be :
;; Originally taken from Bruno Tavernier: http://thread.gmane.org/gmane.emacs.orgmode/31150/focus=31432
(defun my-auto-tex-cmd ()
(if (string-match "YOUR_TAG: value1" (buffer-string))
(do something))
(if (string-match "YOUR_TAG: value2" (buffer-string))
(do something else))
(add-hook 'org-export-latex-after-initial-vars-hook 'my-auto-tex-cmd)
I am developing an emacs major mode for a language (aka mydsl). However, using the techniques on xahlee's site doesn't seem to be working for some reason (possibly older emacs dialect..)
The key issues I am fighting with are (1) highlighting comments is not working and (2), the use of regexp-opt lines is not working.
I've reviewed the GNU manual and looked over cc-mode and elisp mode... those are significantly more complicated than I need.
;;;Standard # to newline comment
;;;Eventually should also have %% to %% multiline block comments
(defun mydsl-comment-dwim (arg)
"comment or uncomment"
(interactive "*P")
(require 'newcomment)
(let
((deactivate-mark nil)
(comment-start "#")
(comment-end "")
comment-dwim arg)))
(defvar mydsl-events
'("reservedword1"
"reservedword2"))
(defvar mydsl-keywords
'("other-keyword" "another-keyword"))
;;Highlight various elements
(setq mydsl-hilite
'(
; stuff between "
("\"\\.\\*\\?" . font-lock-string-face)
; : , ; { } => # $ = are all special elements
(":\\|,\\|;\\|{\\|}\\|=>\\|#\\|$\\|=" . font-lock-keyword-face)
( ,(regexp-opt mydsl-keywords 'words) . font-lock-builtin-face)
( ,(regexp-opt mydsl-events 'words) . font-lock-constant-face)
))
(defvar mydsl-tab-width nil "Width of a tab for MYDSL mode")
(define-derived-mode mydsl-mode fundamental-mode
"MYDSL mode is a major mode for editing MYDSL files"
;Recommended by manual
(kill-all-local-variables)
(setq mode-name "MYDSL script")
(setq font-lock-defaults '((mydsl-hilite)))
(if (null mydsl-tab-width)
(setq tab-width mydsl-tab-width)
(setq tab-width default-tab-width)
)
;Comment definitions
(define-key mydsl-mode-map [remap comment-dwim] 'mydsl-comment-dwim)
(modify-syntax-entry ?# "< b" mydsl-mode-syntax-table)
(modify-syntax-entry ?\n "> b" mydsl-mode-syntax-table)
;;A gnu-correct program will have some sort of hook call here.
)
(provide 'mydsl-mode)
You have a couple of syntactic problems in your code, but you got it nearly correct. Here's my edited version which appears to do the right thing for a buffer in mydsl-mode:
; No changes to the simple vars
(defvar mydsl-events
'("reservedword1"
"reservedword2"))
(defvar mydsl-keywords
'("other-keyword" "another-keyword"))
;; I'd probably put in a default that you want, as opposed to nil
(defvar mydsl-tab-width nil "Width of a tab for MYDSL mode")
;; Two small edits.
;; First is to put an extra set of parens () around the list
;; which is the format that font-lock-defaults wants
;; Second, you used ' (quote) at the outermost level where you wanted ` (backquote)
;; you were very close
(defvar mydsl-font-lock-defaults
`((
;; stuff between "
("\"\\.\\*\\?" . font-lock-string-face)
;; ; : , ; { } => # $ = are all special elements
(":\\|,\\|;\\|{\\|}\\|=>\\|#\\|$\\|=" . font-lock-keyword-face)
( ,(regexp-opt mydsl-keywords 'words) . font-lock-builtin-face)
( ,(regexp-opt mydsl-events 'words) . font-lock-constant-face)
)))
(define-derived-mode mydsl-mode fundamental-mode "MYDSL script"
"MYDSL mode is a major mode for editing MYDSL files"
;; fundamental-mode kills all local variables, no need to do it again
(setq mode-name "MYDSL script")
;; you again used quote when you had '((mydsl-hilite))
;; I just updated the variable to have the proper nesting (as noted above)
;; and use the value directly here
(setq font-lock-defaults mydsl-font-lock-defaults)
;; when there's an override, use it
;; otherwise it gets the default value
(when mydsl-tab-width
(setq tab-width mydsl-tab-width))
;; for comments
;; overriding these vars gets you what (I think) you want
;; they're made buffer local when you set them
(setq comment-start "#")
(setq comment-end "")
(modify-syntax-entry ?# "< b" mydsl-mode-syntax-table)
(modify-syntax-entry ?\n "> b" mydsl-mode-syntax-table)
;;A gnu-correct program will have some sort of hook call here.
)
(provide 'mydsl-mode)