emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/phps-mode 3837d9c 001/405: My initial commit


From: Stefan Monnier
Subject: [elpa] externals/phps-mode 3837d9c 001/405: My initial commit
Date: Sat, 13 Jul 2019 09:59:27 -0400 (EDT)

branch: externals/phps-mode
commit 3837d9cc6d2ed3840ccd2b9edad4f050635e5bbb
Author: Christian Johansson <address@hidden>
Commit: Christian Johansson <address@hidden>

    My initial commit
---
 .gitignore                |    0
 Makefile                  |   23 +
 README.md                 |   13 +
 phps-automation-header.wy |   63 +++
 phps-automation.el        |   32 ++
 phps-flycheck.el          |  106 ++++
 phps-flymake.el           |   75 +++
 phps-font-lock.el         |  145 +++++
 phps-functions.el         |   60 +++
 phps-keywords.wy          |  400 ++++++++++++++
 phps-lexer.el             | 1282 +++++++++++++++++++++++++++++++++++++++++++++
 phps-map.el               |   49 ++
 phps-mode.el              |   94 ++++
 phps-semantic.el          |  489 +++++++++++++++++
 phps-syntax-table.el      |   73 +++
 phps-tags.el              |  159 ++++++
 phps-test-lexer.el        |  243 +++++++++
 phps-test-parser.el       |   52 ++
 tests/php/class.php       |   18 +
 tests/php/functions.php   |    6 +
 tests/php/interfaces.php  |    9 +
 tests/php/namespace.php   |   18 +
 tests/php/namespaces.php  |   19 +
 23 files changed, 3428 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e69de29
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..1beb44f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,23 @@
+EMACS = "/Users/christianjohansson/Documents/emacs/src/emacs"
+EMACS_CMD := $(EMACS) -Q -batch -L .
+
+EL  := phps-mode.el phps-wy.el
+ELC := $(EL:.el=.elc)
+
+clean:
+       rm -f $(ELC)
+
+compile: $(ELC)
+
+%.elc: %.el
+       $(EMACS_CMD) -f batch-byte-compile $<
+
+test: clean lexer-test parser-test
+
+test-lexer:
+       $(EMACS_CMD) -l phps-test-lexer.el
+
+test-parser:
+       $(EMACS_CMD) -l phps-test-parser.el
+
+.PHONY: clean compile test test-lexer test-parser
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..04ba636
--- /dev/null
+++ b/README.md
@@ -0,0 +1,13 @@
+# PHPs - Experiment with a Semantic Mode for Emacs
+
+An Emacs major mode for PHP scripting language which aims at making a full 
semantic integration. Currently at experimental stage.
+
+## Goals
+
+With current progress estimates
+
+* Lexer based on official PHP re2c lexer (90%)
+* Syntax coloring based on lexer tokens (90%)
+* Wisent LALR parser based on official PHP yac parser automatically converter 
(60%)
+* Full integration with Emacs Semantic subsystem (0%)
+* PSR based indentation (0%)
diff --git a/phps-automation-header.wy b/phps-automation-header.wy
new file mode 100644
index 0000000..1772711
--- /dev/null
+++ b/phps-automation-header.wy
@@ -0,0 +1,63 @@
+;;; phps.wy -- Semantic LALR grammar for PHP
+
+;; Copyright (C) 2002-2018 Free Software Foundation, Inc.
+;;
+;; Author: Christian Johansson <address@hidden>
+;; Maintainer: Christian Johansson <address@hidden>
+;; Created: 11 Mar 2018
+;; Keywords: syntax
+
+;; This file is not part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs 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.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+
+
+;; Run `wisent-make-parsers' or "C-c C-c" to generate grammar-file in Emacs 
Lisp.
+;;
+;; Based on the Zend PHP Parser YACC 
https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y
+
+;; Create macros for all macros uses in original YACC, base macro structure on 
semantic-php-wy-macro.el
+
+;; Don't edit phps.wy because it's generated by phps-automation.el and 
phps-automation-header.wy
+
+
+;;; Code:
+
+
+%package phps-mode/tags
+%provide phps-mode/phps-wy
+
+%languagemode phps-mode
+
+%use-macros phps-mode-wy-macro {
+             zend_add_class_modifier
+             zend_add_member_modifier
+             zend_append_str
+             zend_ast_create
+             zend_ast_create_assign_op
+             zend_ast_create_binary_op
+             zend_ast_create_cast
+             zend_ast_create_decl
+             zend_ast_create_ex
+             zend_ast_create_list
+             zend_ast_create_zval_from_str
+             zend_ast_get_str
+             zend_ast_list_add
+             zend_ast_list_rtrim
+             zend_handle_encoding_declaration
+             zend_negate_num_string
+}
diff --git a/phps-automation.el b/phps-automation.el
new file mode 100644
index 0000000..3ab13df
--- /dev/null
+++ b/phps-automation.el
@@ -0,0 +1,32 @@
+;;; phps-automation --- Genereate a Wisent Parser file
+
+
+;;; Commentary:
+
+;;; Uses a parser to convert LALR Yacc grammar to Wisent grammar
+
+;;; AST should be like this: (root (block (rule (logic))))
+
+
+;;; Code:
+
+(add-to-list 'load-path (expand-file-name 
"~/.emacs.d/emacs-wisent-grammar-converter/"))
+(require 'emacs-wisent-grammar-converter)
+
+(let ((php-yacc-url 
"https://raw.githubusercontent.com/php/php-src/master/Zend/zend_language_parser.y";)
+      (php-yacc-file (expand-file-name "zend_language_parser.y"))
+      (wisent-destination (expand-file-name "zend_language_parser.wy")))
+
+  ;; Download Yacc if not available
+  (unless (file-exists-p php-yacc-file)
+    (message "Downloading PHP Yacc grammar..")
+    (url-copy-file php-yacc-url php-yacc-file t t)
+    (message "Downlad completed"))
+
+  ;; Generate grammar
+  (message "Generating Wisent grammar..")
+  (emacs-wisent-grammar-converter/generate-grammar-from-filename php-yacc-file 
wisent-destination)
+  (message "Automation completed"))
+
+(provide 'phps-automation2)
+;;; phps-automation2.el ends here
diff --git a/phps-flycheck.el b/phps-flycheck.el
new file mode 100644
index 0000000..f736662
--- /dev/null
+++ b/phps-flycheck.el
@@ -0,0 +1,106 @@
+;;; phps-mode/phps-flycheck.el --- Flycheck support for PHP with Semantic 
integration
+
+;; Author: Christian Johansson <github.com/cjohansson>
+;; Maintainer: Christian Johansson <github.com/cjohansson>
+;; Created: 3 Mar 2018
+;; Modified: .
+;; Version: 0.1
+;; Keywords: tools, convenience
+;; URL: -
+
+;; Package-Requires: ((emacs "24"))
+
+;; Copyright (C) 2017 Christian Johansson
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; 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.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Spathoftware Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+
+;;; Commentary:
+
+;; Please see README.md from the same repository for extended documentation.
+
+;;; Commentary:
+
+
+;;; Code:
+
+
+(defun phps-mode/flycheck-init ()
+  "Add flycheck support for PHP Semantic mode."
+
+  (when (fboundp 'flycheck-define-checker)
+    (flycheck-define-checker php
+      "A PHP syntax checker using the PHP command line interpreter.
+
+See URL `http://php.net/manual/en/features.commandline.php'."
+      :command ("php" "-l" "-d" "error_reporting=E_ALL" "-d" "display_errors=1"
+                "-d" "log_errors=0" source)
+      :error-patterns
+      ((error line-start (or "Parse" "Fatal" "syntax") " error" (any ":" ",") 
" "
+              (message) " in " (file-name) " on line " line line-end))
+      :modes (php-mode php+-mode phps-mode)
+      :next-checkers ((warning . php-phpmd)
+                      (warning . php-phpcs)))
+
+    (flycheck-define-checker php-phpmd
+      "A PHP style checker using PHP Mess Detector.
+
+See URL `https://phpmd.org/'."
+      :command ("phpmd" source "xml"
+                (eval (flycheck-option-comma-separated-list
+                       flycheck-phpmd-rulesets)))
+      :error-parser flycheck-parse-phpmd
+      :modes (php-mode php+-mode phps-mode)
+      :next-checkers (php-phpcs))
+
+    (flycheck-define-checker php-phpcs
+      "A PHP style checker using PHP Code Sniffer.
+
+Needs PHP Code Sniffer 2.6 or newer.
+
+See URL `http://pear.php.net/package/PHP_CodeSniffer/'."
+      :command ("phpcs" "--report=checkstyle"
+                ;; Use -q flag to force quiet mode
+                ;; Quiet mode prevents errors from extra output when phpcs has
+                ;; been configured with show_progress enabled
+                "-q"
+                (option "--standard=" flycheck-phpcs-standard concat)
+                ;; Pass original file name to phpcs.  We need to concat 
explicitly
+                ;; here, because phpcs really insists to get option and 
argument as
+                ;; a single command line argument :|
+                (eval (when (buffer-file-name)
+                        (concat "--stdin-path=" (buffer-file-name))))
+                ;; Read from standard input
+                "-")
+      :standard-input t
+      :error-parser flycheck-parse-checkstyle
+      :error-filter
+      (lambda (errors)
+        (flycheck-sanitize-errors
+         (flycheck-remove-error-file-names "STDIN" errors)))
+      :modes (php-mode php+-mode phps-mode)
+      ;; phpcs seems to choke on empty standard input, hence skip phpcs if the
+      ;; buffer is empty, see https://github.com/flycheck/flycheck/issues/907
+      :predicate (lambda () (not (flycheck-buffer-empty-p))))
+    )
+  )
+
+
+(provide 'phps-mode/flycheck)
+
+;;; phps-flycheck.el ends here
diff --git a/phps-flymake.el b/phps-flymake.el
new file mode 100644
index 0000000..6da1421
--- /dev/null
+++ b/phps-flymake.el
@@ -0,0 +1,75 @@
+;;; phps-mode/phps-flymake.el --- Major mode for PHP with Semantic integration
+
+;; Author: Christian Johansson <github.com/cjohansson>
+;; Maintainer: Christian Johansson <github.com/cjohansson>
+;; Created: 3 Mar 2018
+;; Modified: .
+;; Version: 0.1
+;; Keywords: tools, convenience
+;; URL: -
+
+;; Package-Requires: ((emacs "24"))
+
+;; Copyright (C) 2017 Christian Johansson
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; 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.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Spathoftware Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+
+;;; Commentary:
+
+;; Please see README.md from the same repository for extended documentation.
+
+;;; Commentary:
+
+
+;;; Code:
+
+
+(require 'flymake)
+
+(defun phps-mode/flymake-init ()
+  "PHP specific init-cleanup routines.
+
+This is an alternative function of `flymake-php-init'.
+Look at the `php-executable' variable instead of the constant \"php\" command."
+
+  (add-to-list 'flymake-allowed-file-name-masks
+               '("\\.php[345s]?\\'"
+                 phps-mode--flymake-init
+                 flymake-simple-cleanup
+                 flymake-get-real-file-name))
+
+  (add-to-list 'flymake-err-line-patterns
+               '("\\(Parse\\|Fatal\\) error: \\(.*?\\) in \\(.*?\\) on line 
\\([0-9]+\\)" 3 4 nil 2))
+
+  (if (boundp 'php-executable)
+      (let* ((temp-file
+              (funcall
+               (eval-when-compile
+                 (if (fboundp 'flymake-proc-init-create-temp-buffer-copy)
+                     'flymake-proc-init-create-temp-buffer-copy
+                   'flymake-init-create-temp-buffer-copy))
+               'flymake-create-temp-inplace))
+             (local-file (file-relative-name
+                          temp-file
+                          (file-name-directory buffer-file-name))))
+        (list php-executable (list "-f" local-file "-l")))))
+
+(provide 'phps-mode/flymake)
+
+;;; phps-flymake.el ends here
diff --git a/phps-font-lock.el b/phps-font-lock.el
new file mode 100644
index 0000000..ca28b42
--- /dev/null
+++ b/phps-font-lock.el
@@ -0,0 +1,145 @@
+;;; phps-mode/phps-font-lock.el --- Font Lock for PHP Semantic
+
+;; Author: Christian Johansson <github.com/cjohansson>
+;; Maintainer: Christian Johansson <github.com/cjohansson>
+;; Created: 3 Mar 2018
+;; Modified: .
+;; Version: 0.1
+;; Keywords: tools, convenience
+;; URL: -
+
+;; Package-Requires: ((emacs "24"))
+
+;; Copyright (C) 2017 Christian Johansson
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; 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.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Spathoftware Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+
+;;; Commentary:
+
+;; Please see README.md from the same repository for extended documentation.
+
+;;; Commentary:
+
+
+;;; Code:
+
+
+(defconst phps-mode/keywords
+  (list
+     "__halt_compiler"
+     "abstract"
+     "and"
+     "array"
+     "as"
+     "break"
+     "callable"
+     "case"
+     "catch"
+     "class"
+     "clone"
+     "const"
+     "continue"
+     "declare"
+     "default"
+     "die"
+     "do"
+     "echo"
+     "else"
+     "elseif"
+     "empty"
+     "enddeclare"
+     "endfor"
+     "endforeach"
+     "endif"
+     "endswitch"
+     "endwhile"
+     "eval"
+     "exit"
+     "extends"
+     "final"
+     "finally"
+     "for"
+     "foreach"
+     "function"
+     "global"
+     "goto"
+     "if"
+     "implements"
+     "include"
+     "include_once"
+     "instanceof"
+     "insteadof"
+     "interface"
+     "isset"
+     "list"
+     "namespace"
+     "new"
+     "or"
+     "print"
+     "private"
+     "protected"
+     "public"
+     "require"
+     "require_once"
+     "return"
+     "static"
+     "switch"
+     "throw"
+     "trait"
+     "try"
+     "unset"
+     "use"
+     "var"
+     "while"
+     "xor"
+     "yield"
+
+     ;; Compile-time constants here
+     "__CLASS__"
+     "__DIR__"
+     "__FILE__"
+     "__FUNCTION__"
+     "__LINE__"
+     "__METHOD__"
+     "__NAMESPACE__"
+     "__TRAIT__"
+   )
+  "Use list of keywords to build regular expression for syntax highlighting.")
+
+(defconst phps-mode/font-lock-keywords
+  (let ((regex (concat "\\<" (regexp-opt phps-mode/keywords t) "\\>")))
+    (list
+     `(,regex . font-lock-builtin-face)
+     '("\\('\\w*'\\)" . font-lock-variable-name-face)))
+  "Minimal highlighting expressions for major mode.")
+
+(defun phps-mode/font-lock-init ()
+  "Apply font-lock."
+
+  (setq font-lock-keywords-only nil)
+
+  ;; This makes it possible to have full control over syntax coloring from the 
lexer
+  (set (make-local-variable 'font-lock-defaults) '(nil t))
+
+  ;; (set (make-local-variable 'font-lock-defaults) 
'(phps-mode/font-lock-keywords))
+  )
+
+(provide 'phps-mode/font-lock)
+
+;;; phps-font-lock.el ends here
diff --git a/phps-functions.el b/phps-functions.el
new file mode 100644
index 0000000..2366c43
--- /dev/null
+++ b/phps-functions.el
@@ -0,0 +1,60 @@
+;;; phps-mode/phps-functions.el --- Mode functions for PHPs
+
+;; Author: Christian Johansson <github.com/cjohansson>
+;; Maintainer: Christian Johansson <github.com/cjohansson>
+;; Created: 3 Mar 2018
+;; Modified: .
+;; Version: 0.1
+;; Keywords: tools, convenience
+;; URL: -
+
+;; Package-Requires: ((emacs "24"))
+
+;; Copyright (C) 2017 Christian Johansson
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; 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.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Spathoftware Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+
+;;; Commentary:
+
+
+;;; Code:
+
+
+(defun phps-mode/indent-line ()
+  "Indent line."
+  (save-excursion
+    (move-beginning-of-line nil)
+    )
+  )
+
+(defun phps-mode/indent-region ()
+  "Indent region.")
+
+(defun phps-mode/functions-init ()
+  "PHP specific init-cleanup routines."
+
+  ;; (set (make-local-variable 'indent-line-function) 'phps-mode/indent-line)
+  ;; (set (make-local-variable 'indent-line-function) 'phps-mode/indent-region)
+
+  )
+
+
+(provide 'phps-mode/functions)
+
+;;; phps-functions.el ends here
diff --git a/phps-keywords.wy b/phps-keywords.wy
new file mode 100644
index 0000000..d39eecc
--- /dev/null
+++ b/phps-keywords.wy
@@ -0,0 +1,400 @@
+;;; KEYWORDS
+;; -----------------
+;; Keyword terminals
+;; -----------------
+
+;; Generate a keyword analyzer
+;; https://secure.php.net/manual/en/reserved.keywords.php
+;; https://secure.php.net/manual/en/language.constants.predefined.php
+
+%type  <keyword> ;;syntax "\\(\\sw\\|\\s_\\)+" matchdatatype keyword
+
+%keyword __CLASS__ "__CLASS__"
+%put __CLASS__ summary
+"The class name. The class name includes the namespace it was declared in 
(e.g. Foo\\Bar)."
+
+%keyword __CONSTRUCT "__construct"
+%put     __CONSTRUCT summary
+"Class constructor method"
+
+%keyword __DIR__ "__DIR__"
+%put __DIR__ summary
+"The directory of the file."
+
+%keyword __FILE__ "__FILE__"
+%put __FILE__ summary
+"The full path and filename of the file with symlinks resolved."
+
+%keyword __FUNCTION__ "__FUNCTION__"
+%put __FUNCTION__ summary
+"The current function name."
+
+%keyword __LINE__ "__LINE__"
+%put __LINE__ summary
+"The current line number of the file."
+
+%keyword __METHOD__ "__METHOD__"
+%put __METHOD__ summary
+"The current method name."
+
+%keyword __NAMESPACE__ "__NAMESPACE__"
+%put __NAMESPACE__ summary
+"The current namespace name."
+
+%keyword __TRAIT__ "__TRAIT__"
+%put __TRAIT__ summary
+"The trait name. The trait name includes the namespace it was declared in 
(e.g. Foo\\Bar)."
+
+%keyword HALT_COMPILER     "__halt_compiler"
+%put     HALT_COMPILER summary
+"Halts the execution of the compiler. This can be useful to embed data in PHP 
scripts, like the installation files."
+
+%keyword ABSTRACT     "abstract"
+%put     ABSTRACT summary
+"Class|Method declaration modifier: abstract {class <name>|<name>} <name> ..." 
;; TODO Methods too?
+
+%keyword AND2     "and"
+%put     AND2 summary
+"<expr> and <expr>"
+
+%keyword ARRAY     "array"
+%put     ARRAY summary
+"array(<expr>)"
+
+%keyword AS     "as"
+%put     AS summary
+"foreach(<expr> as <expr) | use <expr> as <expr>"
+
+%keyword BREAK        "break"
+%put     BREAK summary
+"break[ <levels>];"
+
+%keyword CALLABLE         "callable"
+%put     CALLABLE summary
+"callable $<stmt>"
+
+%keyword CASE         "case"
+%put     CASE summary
+"switch(<expr>) {case <const-expr>: <stmts> ... }"
+
+%keyword CATCH        "catch"
+%put     CATCH summary
+"try {<stmts>} catch(<parm>) {<stmts>} ... "
+
+%keyword CLASS        "class"
+%put     CLASS summary
+"Class declaration: class <name> { <exprs> }"
+
+%keyword CLONE        "clone"
+%put     CLONE summary
+"<stmt> = clone <stmt>;"
+
+%keyword CONST        "const"
+%put     CONST summary
+"const <stmt> = <stmt>;"
+
+%keyword CONTINUE     "continue"
+%put     CONTINUE summary
+"continue[ <levels>];"
+
+%keyword DECLARE      "declare"
+%put     DECLARE summary
+"declare (<expr>) { <stmts> }"
+
+%keyword DEFAULT      "default"
+%put     DEFAULT summary
+"switch(<expr>) { case <expr> { ... } default: { <stmts> } }"
+
+%keyword DIE           "die"
+%put     DIE summary
+"die([<stmt>]);"
+
+%keyword DO           "do"
+%put     DO summary
+"do { <stmts> } while (<expr>);"
+
+%keyword ECHO       "echo"
+%put     ECHO summary
+"echo <stmts>;"
+
+%keyword ELSE         "else"
+%put     ELSE summary
+"if (<expr>) { <stmt> } else { <stmt> }"
+
+%keyword ELSEIF         "elseif"
+%put     ELSEIF summary
+"if (<expr>) { <stmt> } elseif { <stmt> }"
+
+%keyword EMPTY         "empty"
+%put     EMPTY summary
+"empty(<stmt>): bool"
+
+%keyword ENDDECLARE "enddeclare"
+%put     ENDDECLARE summary
+"declare(<expr>): <exprs> enddeclare;"
+
+%keyword ENDFOR "endfor"
+%put     ENDFOR summary
+"for (<start>; <condition>; <increment>): <exprs>; endfor;"
+
+%keyword ENDFOREACH "endforeach"
+%put     ENDFOREACH summary
+"foreach (<stmt> as <expr>): <exprs>; endforeach;"
+
+%keyword ENDIF "endif"
+%put     ENDIF summary
+"if (<stmt>): <exprs>; endif;"
+
+%keyword ENDSWITCH "endswitch"
+%put     ENDSWITCH summary
+"switch (<stmt>): <exprs>; endswitch;"
+
+%keyword ENDWHILE "endwhile"
+%put     ENDWHILE summary
+"while (<stmt>): <exprs>; endwhile;"
+
+%keyword EVAL "eval"
+%put     EVAL summary
+"eval(<exprs>)"
+
+%keyword EXIT "exit"
+%put     EXIT summary
+"exit[ <code>];"
+
+%keyword EXTENDS      "extends"
+%put     EXTENDS summary
+"SuperClass|SuperInterfaces declaration: extends <name> [, ...]"
+
+%keyword FINAL        "final"
+%put     FINAL summary
+"Class|Member declaration modifier: final {class|<type>} <name> ..."
+
+%keyword FINALLY      "finally"
+%put     FINALLY summary
+"try {<stmts>} ... finally {<stmts>}"
+
+%keyword FOR          "for"
+%put     FOR summary
+"for ([<init-expr>]; [<expr>]; [<update-expr>]) { <stmts> }"
+
+%keyword FOREACH          "foreach"
+%put     FOREACH summary
+"foreach (<expr> as <expr>) { <exprs> }"
+
+%keyword FUNCTION          "function"
+%put     FUNCTION summary
+"function <name>(<args>) { <exprs> }"
+
+%keyword GOTO         "goto"
+%put     GOTO summary
+"goto <stmt>;"
+
+%keyword IF           "if"
+%put     IF summary
+"if (<expr>) { <stmts> } [else { <stmt> }]"
+
+%keyword IMPLEMENTS   "implements"
+%put     IMPLEMENTS summary
+"Class SuperInterfaces declaration: implements <name> [, ...]"
+
+%keyword INCLUDE       "include"
+%put     INCLUDE summary
+"include(<stmt>);"
+
+%keyword INCLUDE_ONCE       "include_once"
+%put     INCLUDE_ONCE summary
+"include_once(<stmt>);"
+
+%keyword INSTANCEOF   "instanceof"
+%put     INSTANCEOF summary
+"<expr> instanceof <expr>"
+
+%keyword INSTEADOF   "insteadof"
+%put     INSTEADOF summary
+"<expr> insteadof <expr>"
+
+%keyword INTERFACE    "interface"
+%put     INTERFACE summary
+"Interface declaration: interface <name>"
+
+%keyword ISSET    "isset"
+%put     ISSET summary
+"isset(<expr>): bool"
+
+%keyword LIST    "list"
+%put     LIST summary
+"list(<stmt>[, <stmts]) = $list;"
+
+%keyword NAMESPACE      "namespace"
+%put     NAMESPACE summary
+"Namespace declaration: namespace <stmt>"
+
+%keyword NEW          "new"
+%put     NEW summary
+"new <type>"
+
+%keyword OR           "or"
+%put     OR summary
+"(<stmt> or <stmt>): bool"
+
+%keyword PRINT           "print"
+%put     PRINT summary
+"print <stmt>[,<stmt>,...];"
+
+%keyword PRIVATE      "private"
+%put     PRIVATE summary
+"Access level modifier: private {method|field} ..."
+
+%keyword PROTECTED    "protected"
+%put     PROTECTED summary
+"Access level modifier: protected {method|field} ..."
+
+%keyword PUBLIC       "public"
+%put     PUBLIC summary
+"Access level modifier: public {method|field} ..."
+
+%keyword REQUIRE       "require"
+%put     REQUIRE summary
+"require(<expr>);"
+
+%keyword REQUIRE_ONCE       "require_once"
+%put     REQUIRE_ONCE summary
+"require_once(<expr>);"
+
+%keyword RETURN       "return"
+%put     RETURN summary
+"return [<expr>];"
+
+%keyword SELF       "self"
+%put     SELF summary
+"Reference to current object" ;; TODO Update description
+
+%keyword STATIC       "static"
+%put     STATIC summary
+"Declaration modifier: static {method|field} ..."
+
+%keyword SWITCH       "switch"
+%put     SWITCH summary
+"switch(<expr>) {[case <const-expr>: <stmts> ...] [default: <stmts>]}"
+
+%keyword THIS         "$this"
+%put     THIS summary
+"Reference to current object"
+
+%keyword THROW        "throw"
+%put     THROW summary
+"throw <expr> ;"
+
+%keyword TRAIT        "trait"
+%put     TRAIT summary
+"trait <stmt> { <stmts> }"
+
+%keyword TRY          "try"
+%put     TRY summary
+"try {<stmts>} [catch(<parm>) {<stmts>} ...] [finally {<stmts>}]"
+
+%keyword UNSET         "unset"
+%put     UNSET summary
+"unset(<stmt>[, <stmt>, ...])"
+
+%keyword USE     "use"
+%put     USE summary
+"use <stmt>[ as <expr>];"
+
+%keyword VAR     "var"
+%put     VAR summary
+"Public field declaration. var <stmt> = <expr>"
+
+%keyword WHILE        "while"
+%put     WHILE summary
+"while (<expr>) <stmt> | do <stmt> while (<expr>);"
+
+%keyword XOR        "xor"
+%put     XOR summary
+"(<stmt> xor <stmt>): bool"
+
+%keyword YIELD        "yield"
+%put     YIELD summary
+"yield <expr>;"
+
+;; --------------------------
+;; Official PHPDoc line tags
+;; --------------------------
+
+;; PHPDoc tags are identified by a 'phpdoc' keyword property.  The
+;; value of this property must be itself a property list where the
+;; following properties are recognized:
+;;
+;; - `seq' (mandatory) is the tag sequence number used to check if tags
+;;   are correctly ordered in a PHPDoc comment block.
+;;
+;; - `usage' (mandatory) is the list of token categories for which this
+;;   documentation tag is allowed.
+;;
+;; - `opt' (optional) if non-nil indicates this is an optional tag.
+;;   By default tags are mandatory.
+;;
+;; - `with-name' (optional) if non-nil indicates that this tag is
+;;   followed by an identifier like in "@param <var-name> description"
+;;   or "@exception <class-name> description".
+;;
+;; - `with-ref' (optional) if non-nil indicates that the tag is
+;;   followed by a reference like in "@see <reference>".
+
+;; https://docs.phpdoc.org/references/phpdoc/index.html
+;; TODO Verify parameters below
+
+%keyword _API          "@api"
+%put     _API          phpdoc (seq 1 usage (type))
+%keyword _AUTHOR       "@author"
+%put     _AUTHOR       phpdoc (seq 1 usage (type))
+%keyword _CATEGORY     "@category"
+%put     _CATEGORY      phpdoc (seq 1 usage (type))
+%keyword _EXAMPLE      "@example"
+%put     _EXAMPLE      phpdoc (seq 1 usage (type))
+%keyword _FILESOURCE   "@filesource"
+%put     _FILESOURCE   phpdoc (seq 1 usage (type))
+%keyword _GLOBAL       "@global"
+%put     _GLOBAL       phpdoc (seq 2 usage (type))
+%keyword _IGNORE       "@ignore"
+%put     _IGNORE       phpdoc (seq 2 usage (type))
+%keyword _INTERNAL     "@internal"
+%put     _INTERNAL     phpdoc (seq 2 usage (type))
+%keyword _LICENSE     "@license"
+%put     _LICENSE     phpdoc (seq 2 usage (type))
+%keyword _LINK        "@link"
+%put     _LINK        phpdoc (seq 2 usage (type))
+%keyword _METHOD      "@method"
+%put     _METHOD      phpdoc (seq 2 usage (type))
+%keyword _PACKAGE     "@package"
+%put     _PACKAGE     phpdoc (seq 2 usage (type))
+%keyword _PARAM       "@param"
+%put     _PARAM       phpdoc (seq 3 usage (function) with-name t)
+%keyword _PROPERTY    "@property"
+%put     _PROPERTY    phpdoc (seq 3 usage (function) with-name t)
+%keyword _PROPERTY_READ   "@property-read"
+%put     _PROPERTY_READ    phpdoc (seq 3 usage (function) with-name t)
+%keyword _PROPERTY_WRITE   "@property-write"
+%put     _PROPERTY_WRITE    phpdoc (seq 3 usage (function) with-name t)
+%keyword _RETURN      "@return"
+%put     _RETURN      phpdoc (seq 4 usage (function))
+%keyword _SEE         "@see"
+%put     _SEE         phpdoc (seq 7 usage (type function variable) opt t 
with-ref t)
+%keyword _SINCE       "@since"
+%put     _SINCE       phpdoc (seq 8 usage (type function variable) opt t)
+%keyword _SOURCE      "@source"
+%put     _SOURCE      phpdoc (seq 8 usage (type function variable) opt t)
+%keyword _SUBPACKAGE  "@subpackage"
+%put     _SUBPACKAGE  phpdoc (seq 8 usage (type function variable) opt t)
+%keyword _THROWS      "@throws"
+%put     _THROWS      phpdoc (seq 6 usage (function) with-name t)
+%keyword _TODO      "@todo"
+%put     _TODO      phpdoc (seq 6 usage (function) with-name t)
+%keyword _USES      "@uses"
+%put     _USES      phpdoc (seq 6 usage (function) with-name t)
+%keyword _USED_BY   "@used-by"
+%put     _USES_BY   phpdoc (seq 6 usage (function) with-name t)
+%keyword _VAR   "@var"
+%put     _VAR   phpdoc (seq 6 usage (function) with-name t)
+%keyword _VERSION     "@version"
+%put     _VERSION     phpdoc (seq 2 usage (type))
diff --git a/phps-lexer.el b/phps-lexer.el
new file mode 100644
index 0000000..4ba9eef
--- /dev/null
+++ b/phps-lexer.el
@@ -0,0 +1,1282 @@
+;;; phps-mode/phps-lexer.wy -- Lexer for PHP
+
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+;;
+;; Author: Christian Johansson <address@hidden>
+;; Maintainer: Christian Johansson <address@hidden>
+;; Created: 11 Mar 2018
+;; Keywords: syntax
+
+;; This file is not part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs 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.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+
+
+;; Based on the Zend PHP Lexer and Parser 
https://github.com/php/php-src/blob/master/Zend/zend_language_scanner.l
+;; which is using re2c.
+;;
+;; NOTE Files of interest:
+;; - zend_language_scanner.l
+
+
+;;; Code:
+
+
+(require 'semantic)
+(require 'semantic/lex)
+
+;; Define the lexer for this grammar
+
+;; Make sure `semantic-lex-syntax-modifications' is correct since lexer is 
dependent on Emacs syntax-table
+
+
+;; SETTINGS
+
+
+;; @see https://secure.php.net/manual/en/language.types.integer.php
+(defvar phps-mode/long-limit 2147483648
+  "Limit for 32-bit integer.")
+
+(defvar phps-mode/PARSER_MODE t
+  "Flag whether we is using parser-mode or not.")
+
+(defvar phps-mode/SHORT_TAGS t
+  "Flag whether we support short-tags or not.")
+
+
+;; FLAGS/SIGNALS
+
+
+(defvar phps-mode/declaring_namespace nil
+  "Flag whether we are declaring namespace.")
+
+(defvar phps-mode/prepend_trailing_brace nil
+  "Flag whether we should prepend trailing brace.")
+
+(defvar phps-mode/STATE nil
+  "Current state.")
+
+(defvar phps-mode/EXPECTED nil
+  "Flag whether something is expected or not.")
+
+(defvar phps-mode/state_stack nil
+  "Stack of states.")
+
+(defvar phps-mode/heredoc_label_stack (list)
+  "The current heredoc_label.")
+
+(defconst phps-mode/ST_INITIAL 0
+  "Flag for initial state.")
+
+(defconst phps-mode/ST_IN_SCRIPTING 1
+  "Flag whether we are in script or not.")
+
+(defconst phps-mode/ST_BACKQUOTE 2
+  "Flag whether we are inside backquote or not.")
+
+(defconst phps-mode/ST_DOUBLE_QUOTES 3
+  "Flag whether we are inside double quotes or not.")
+
+(defconst phps-mode/ST_END_HEREDOC 4
+  "Flag whether we are inside end heredoc or not.")
+
+(defconst phps-mode/ST_HEREDOC 5
+  "Flag whether we are inside heredoc or not.")
+
+(defconst phps-mode/ST_LOOKING_FOR_PROPERTY 6
+  "Flag whether we are looking for property or not.")
+
+(defconst phps-mode/ST_LOOKING_FOR_VARNAME 7
+  "Flag whether we are looking for variable name or not.")
+
+(defconst phps-mode/ST_NOWDOC 8
+  "Flag whether we are inside nowdoc or not.")
+
+(defconst phps-mode/ST_VAR_OFFSET 9
+  "Flag whether we are looking for variable offset or not.")
+
+
+;; REGULAR EXPRESSIONS
+
+
+(defvar phps-mode/BNUM "0b[01]+"
+  "Boolean number.")
+
+(defvar phps-mode/HNUM "0x[0-9a-fA-F]+"
+  "Hexadecimal number.")
+
+(defvar phps-mode/LNUM "[0-9]+"
+  "Long number.")
+
+(defvar phps-mode/DNUM "\\([0-9]*\\.[0-9]+\\)\\|\\([0-9]+\\.[0-9]*\\)"
+  "Double number.")
+
+(defvar phps-mode/EXPONENT_DNUM
+  (format "\\(\\(%s\\|%s\\)[eE][\\+-]?%s\\)"
+          phps-mode/LNUM
+          phps-mode/DNUM
+          phps-mode/LNUM)
+  "Exponent double number.")
+
+(defvar phps-mode/LABEL
+  "[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*"
+  "Labels are used for names.")
+
+(defvar phps-mode/WHITESPACE "[ \n\r\t]+"
+  "Whitespace.")
+
+(defvar phps-mode/TABS_AND_SPACES "[ \t]*"
+  "Tabs and whitespaces.")
+
+(defvar phps-mode/TOKENS "[;\\:,.()^&+-/*=%!~\\$<>?@]"
+  "Tokens.")
+
+(defvar phps-mode/ANY_CHAR ".\\|\n"
+  "Any character.  The Zend equivalent is [^] but is not possible in Emacs 
Lisp.")
+
+(defvar phps-mode/NEWLINE "\\(\r\\|\n\\|\r\n\\)"
+  "Newline characters.")
+
+
+;; FUNCTIONS
+
+
+(defun phps-mode/BEGIN (state)
+  "Begin STATE."
+  (setq phps-mode/STATE state)
+  ;; (message "Begun state %s" state)
+  )
+
+;; _yy_push_state
+(defun phps-mode/yy_push_state (state)
+  "Add STATE to stack and then begin state."
+  (let ((old-state (car phps-mode/state_stack)))
+    (when (not old-state)
+      (setq old-state phps-mode/STATE))
+    (if (not phps-mode/state_stack)
+        (setq phps-mode/state_stack (list old-state))
+      (push old-state phps-mode/state_stack))
+    ;; (message "Added state %s to stack" old-state)
+    )
+  (phps-mode/BEGIN state))
+
+(defun phps-mode/yy_pop_state ()
+  "Pop current state from stack."
+  (let* ((old-state (pop phps-mode/state_stack))
+         (new-state (car phps-mode/state_stack)))
+    ;; (message "Going back to poppped state %s" old-state)
+    ;; (message "Ended state %s, going back to %s" old-state new-state)
+    (if old-state
+        (phps-mode/BEGIN old-state)
+      (display-warning "phps-mode" "PHPs Lexer Error - Going back to nil?"))
+    ))
+
+(defun phps-mode/MOVE_FORWARD (position)
+  "Move forward to POSITION."
+  (setq semantic-lex-end-point position))
+
+;; TODO Use font-lock-syntactic-face-function instead?
+(defun phps-mode/COLOR_SYNTAX (token start end)
+  "Syntax coloring for TOKEN from START to END."
+  ;; Syntax coloring
+  ;; see 
https://www.gnu.org/software/emacs/manual/html_node/elisp/Faces-for-Font-Lock.html#Faces-for-Font-Lock
+  (cond
+
+   ((or
+     (string= token 'T_OBJECT_OPERATOR)
+     (string= token 'T_PAAMAYIM_NEKUDOTAYIM)
+     (string= token 'T_NS_SEPARATOR)
+     (string= token 'T_VARIABLE)
+     (string= token 'T_STRING_VARNAME)
+     (string= token 'T_NUM_STRING)
+     (string= token 'T_DOLLAR_OPEN_CURLY_BRACES)
+     (string= token 'T_CURLY_OPEN)
+     (string= token 'T_STRING)
+     (string= token "]")
+     (string= token "{")
+     (string= token "}")
+     )
+    (overlay-put (make-overlay start end) 'font-lock-face 
'font-lock-variable-name-face))
+
+   ((string= token 'T_COMMENT)
+    (add-text-properties start end '(font-lock-face font-lock-comment-face)))
+
+   ((string= token 'T_DOC_COMMENT)
+    (overlay-put (make-overlay start end) 'font-lock-face 
'font-lock-comment-delimiter-face))
+
+   ((or
+     (string= token 'T_CONSTANT_ENCAPSED_STRING)
+     (string= token 'T_ENCAPSED_AND_WHITESPACE)
+     (string= token 'T_DNUMBER)
+     (string= token 'T_LNUMBER)
+     )
+    (overlay-put (make-overlay start end) 'font-lock-face 
'font-lock-string-face))
+
+   ((or
+     (string= token 'T_EXIT)
+     (string= token 'T_DIE)
+     (string= token 'T_FUNCTION)
+     (string= token 'T_CONST)
+     (string= token 'T_RETURN)
+     (string= token 'T_YIELD_FROM)
+     (string= token 'T_YIELD)
+     (string= token 'T_TRY)
+     (string= token 'T_CATCH)
+     (string= token 'T_FINALLY)
+     (string= token 'T_THROW)
+     (string= token 'T_IF)
+     (string= token 'T_ELSEIF)
+     (string= token 'T_ENDIF)
+     (string= token 'T_ELSE)
+     (string= token 'T_WHILE)
+     (string= token 'T_ENDWHILE)
+     (string= token 'T_DO)
+     (string= token 'T_FOREACH)
+     (string= token 'T_ENDFOREACH)
+     (string= token 'T_FOR)
+     (string= token 'T_ENDFOR)
+     (string= token 'T_DECLARE)
+     (string= token 'T_ENDDECLARE)
+     (string= token 'T_INSTANCEOF)
+     (string= token 'T_AS)
+     (string= token 'T_SWITCH)
+     (string= token 'T_ENDSWITCH)
+     (string= token 'T_CASE)
+     (string= token 'T_DEFAULT)
+     (string= token 'T_BREAK)
+     (string= token 'T_CONTINUE)
+     (string= token 'T_GOTO)
+     (string= token 'T_ECHO)
+     (string= token 'T_PRINT)
+     (string= token 'T_CLASS)
+     (string= token 'T_INTERFACE)
+     (string= token 'T_TRAIT)
+     (string= token 'T_EXTENDS)
+     (string= token 'T_IMPLEMENTS)
+     (string= token 'T_NEW)
+     (string= token 'T_CLONE)
+     (string= token 'T_VAR)
+     (string= token 'T_EVAL)
+     (string= token 'T_INCLUDE_ONCE)
+     (string= token 'T_INCLUDE)
+     (string= token 'T_REQUIRE_ONCE)
+     (string= token 'T_REQUIRE)
+     (string= token 'T_NAMESPACE)
+     (string= token 'T_USE)
+     (string= token 'T_INSTEADOF)
+     (string= token 'T_GLOBAL)
+     (string= token 'T_ISSET)
+     (string= token 'T_EMPTY)
+     (string= token 'T_HALT_COMPILER)
+     (string= token 'T_STATIC)
+     (string= token 'T_ABSTRACT)
+     (string= token 'T_FINAL)
+     (string= token 'T_PRIVATE)
+     (string= token 'T_PROTECTED)
+     (string= token 'T_PUBLIC)
+     (string= token 'T_UNSET)
+     (string= token 'T_LIST)
+     (string= token 'T_ARRAY)
+     (string= token 'T_CALLABLE)
+     )
+    (overlay-put (make-overlay start end) 'font-lock-face 
'font-lock-keyword-face))
+
+
+   ((or
+     (string= token 'T_OPEN_TAG)
+     (string= token 'T_OPEN_TAG_WITH_ECHO)
+     (string= token 'T_CLOSE_TAG)
+     (string= token 'T_START_HEREDOC)
+     (string= token 'T_END_HEREDOC)
+     (string= token "`")
+     (string= token "\"")
+     (string= token ";")
+     (string= token 'T_ELLIPSIS)
+     (string= token 'T_COALESCE)
+     (string= token 'T_DOUBLE_ARROW)
+     (string= token 'T_INC)
+     (string= token 'T_DEC)
+     (string= token 'T_IS_IDENTICAL)
+     (string= token 'T_IS_NOT_IDENTICAL)
+     (string= token 'T_IS_EQUAL)
+     (string= token 'T_IS_NOT_EQUAL)
+     (string= token 'T_SPACESHIP)
+     (string= token 'T_IS_SMALLER_OR_EQUAL)
+     (string= token 'T_IS_GREATER_OR_EQUAL)
+     (string= token 'T_PLUS_EQUAL)
+     (string= token 'T_MINUS_EQUAL)
+     (string= token 'T_MUL_EQUAL)
+     (string= token 'T_POW_EQUAL)
+     (string= token 'T_POW)
+     (string= token 'T_DIV_EQUAL)
+     (string= token 'T_CONCAT_EQUAL)
+     (string= token 'T_MOD_EQUAL)
+     (string= token 'T_SL_EQUAL)
+     (string= token 'T_SR_EQUAL)
+     (string= token 'T_AND_EQUAL)
+     (string= token 'T_OR_EQUAL)
+     (string= token 'T_XOR_EQUAL)
+     (string= token 'T_BOOLEAN_OR)
+     (string= token 'T_BOOLEAN_AND)
+     (string= token 'T_BOOLEAN_XOR)
+     (string= token 'T_LOGICAL_XOR)
+     (string= token 'T_LOGICAL_OR)
+     (string= token 'T_LOGICAL_AND)
+     (string= token 'T_SL)
+     (string= token 'T_SR)
+     (string= token 'T_CLASS_C)
+     (string= token 'T_TRAIT_C)
+     (string= token 'T_FUNC_C)
+     (string= token 'T_METHOD_C)
+     (string= token 'T_LINE)
+     (string= token 'T_FILE)
+     (string= token 'T_DIR)
+     (string= token 'T_NS_C)
+     (string= token 'T_INT_CAST)
+     (string= token 'T_DOUBLE_CAST)
+     (string= token 'T_STRING_CAST)
+     (string= token 'T_ARRAY_CAST)
+     (string= token 'T_OBJECT_CAST)
+     (string= token 'T_BOOL_CAST)
+     (string= token 'T_UNSET_CAST)
+     )
+    (overlay-put (make-overlay start end) 'font-lock-face 
'font-lock-constant-face))
+
+   ((string= token 'T_ERROR)
+    (overlay-put (make-overlay start end)  'font-lock-face 
'font-lock-warning-face))
+
+   ))
+
+(defun phps-mode/RETURN_TOKEN (token start end)
+  "Push TOKEN to list with START and END."
+
+  (phps-mode/COLOR_SYNTAX token start end)
+
+  (when (and
+       phps-mode/prepend_trailing_brace
+       (> end (- (point-max) 2)))
+    ;; (message "Adding trailing brace")
+    (setq phps-mode/prepend_trailing_brace nil)
+    (phps-mode/RETURN_TOKEN "}" (- end 1) end))
+
+  (semantic-lex-push-token
+   (semantic-lex-token token start end))
+
+  )
+
+
+;; LEXERS
+
+
+(define-lex-analyzer phps-mode/lex--INITIAL
+  "<?=,<?php,<?,end|inline_char_handler"
+  (= phps-mode/STATE phps-mode/ST_INITIAL)
+  (cond
+
+   ((looking-at "<\\?=")
+    (let ((start (match-beginning 0))
+          (end (match-end 0)))
+      (phps-mode/BEGIN phps-mode/ST_IN_SCRIPTING)
+      (if phps-mode/PARSER_MODE
+          (phps-mode/RETURN_TOKEN 'T_ECHO start end))
+        (phps-mode/RETURN_TOKEN 'T_OPEN_TAG_WITH_ECHO start end)
+      ))
+
+   ((looking-at "<\\?php\\([ \t]\\|\n\\)")
+    (let ((start (match-beginning 0))
+          (end (match-end 0)))
+      (phps-mode/BEGIN phps-mode/ST_IN_SCRIPTING)
+      (when phps-mode/EXPECTED
+          ;; skip-token?
+          )
+      (phps-mode/RETURN_TOKEN 'T_OPEN_TAG start end)
+      ))
+
+   ((looking-at "<\\?")
+    (when phps-mode/SHORT_TAGS
+      (let ((start (match-beginning 0))
+            (end (match-end 0)))
+        (phps-mode/BEGIN phps-mode/ST_IN_SCRIPTING)
+        (phps-mode/RETURN_TOKEN 'T_OPEN_TAG start end)
+        )))
+
+   ((looking-at phps-mode/ANY_CHAR)
+    (let ((string-start (search-forward "<?" nil t)))
+      (if string-start
+          (phps-mode/MOVE_FORWARD (- string-start 2))
+        (phps-mode/MOVE_FORWARD (point-max)))))
+
+   ))
+
+(define-lex-analyzer phps-mode/lex--ST_IN_SCRIPTING
+  "<ST_IN_SCRIPTING>"
+  (= phps-mode/STATE phps-mode/ST_IN_SCRIPTING)
+  (cond
+
+   ((looking-at "exit")
+    (phps-mode/RETURN_TOKEN 'T_EXIT (match-beginning 0) (match-end 0)))
+   ((looking-at "die")
+    (phps-mode/RETURN_TOKEN 'T_DIE (match-beginning 0) (match-end 0)))
+   ((looking-at "function")
+    (phps-mode/RETURN_TOKEN 'T_FUNCTION (match-beginning 0) (match-end 0)))
+   ((looking-at "const")
+    (phps-mode/RETURN_TOKEN 'T_CONST (match-beginning 0) (match-end 0)))
+   ((looking-at "return")
+    (phps-mode/RETURN_TOKEN 'T_RETURN (match-beginning 0) (match-end 0)))
+   ((looking-at (concat "yield" phps-mode/WHITESPACE "from" 
"[^a-zA-Z0-9_\x80-\xff]"))
+      (phps-mode/RETURN_TOKEN 'T_YIELD_FROM (match-beginning 0) (match-end 0)))
+   ((looking-at "yield")
+      (phps-mode/RETURN_TOKEN 'T_YIELD (match-beginning 0) (match-end 0)))
+   ((looking-at "try")
+    (phps-mode/RETURN_TOKEN 'T_TRY (match-beginning 0) (match-end 0)))
+   ((looking-at "catch")
+      (phps-mode/RETURN_TOKEN 'T_CATCH (match-beginning 0) (match-end 0)))
+   ((looking-at "finally")
+      (phps-mode/RETURN_TOKEN 'T_FINALLY (match-beginning 0) (match-end 0)))
+   ((looking-at "throw")
+    (phps-mode/RETURN_TOKEN 'T_THROW (match-beginning 0) (match-end 0)))
+   ((looking-at "if")
+    (phps-mode/RETURN_TOKEN 'T_IF (match-beginning 0) (match-end 0)))
+   ((looking-at "elseif")
+    (phps-mode/RETURN_TOKEN 'T_ELSEIF (match-beginning 0) (match-end 0)))
+   ((looking-at "endif")
+    (phps-mode/RETURN_TOKEN 'T_ENDIF (match-beginning 0) (match-end 0)))
+   ((looking-at "else")
+    (phps-mode/RETURN_TOKEN 'T_ELSE (match-beginning 0) (match-end 0)))
+   ((looking-at "while")
+    (phps-mode/RETURN_TOKEN 'T_WHILE (match-beginning 0) (match-end 0)))
+   ((looking-at "endwhile")
+    (phps-mode/RETURN_TOKEN 'T_ENDWHILE (match-beginning 0) (match-end 0)))
+   ((looking-at "do")
+      (phps-mode/RETURN_TOKEN 'T_DO (match-beginning 0) (match-end 0)))
+   ((looking-at "foreach")
+    (phps-mode/RETURN_TOKEN 'T_FOREACH (match-beginning 0) (match-end 0)))
+   ((looking-at "endforeach")
+    (phps-mode/RETURN_TOKEN 'T_ENDFOREACH (match-beginning 0) (match-end 0)))
+   ((looking-at "for")
+    (phps-mode/RETURN_TOKEN 'T_FOR (match-beginning 0) (match-end 0)))
+   ((looking-at "endfor")
+    (phps-mode/RETURN_TOKEN 'T_ENDFOR (match-beginning 0) (match-end 0)))
+   ((looking-at "declare")
+    (phps-mode/RETURN_TOKEN 'T_DECLARE (match-beginning 0) (match-end 0)))
+   ((looking-at "enddeclare")
+    (phps-mode/RETURN_TOKEN 'T_ENDDECLARE (match-beginning 0) (match-end 0)))
+   ((looking-at "instanceof")
+    (phps-mode/RETURN_TOKEN 'T_INSTANCEOF (match-beginning 0) (match-end 0)))
+   ((looking-at "as")
+    (phps-mode/RETURN_TOKEN 'T_AS (match-beginning 0) (match-end 0)))
+   ((looking-at "switch")
+    (phps-mode/RETURN_TOKEN 'T_SWITCH (match-beginning 0) (match-end 0)))
+   ((looking-at "endswitch")
+    (phps-mode/RETURN_TOKEN 'T_ENDSWITCH (match-beginning 0) (match-end 0)))
+   ((looking-at "case")
+    (phps-mode/RETURN_TOKEN 'T_CASE (match-beginning 0) (match-end 0)))
+   ((looking-at "default")
+    (phps-mode/RETURN_TOKEN 'T_DEFAULT (match-beginning 0) (match-end 0)))
+   ((looking-at "break")
+    (phps-mode/RETURN_TOKEN 'T_BREAK (match-beginning 0) (match-end 0)))
+   ((looking-at "continue")
+    (phps-mode/RETURN_TOKEN 'T_CONTINUE (match-beginning 0) (match-end 0)))
+   ((looking-at "goto")
+    (phps-mode/RETURN_TOKEN 'T_GOTO (match-beginning 0) (match-end 0)))
+   ((looking-at "echo")
+    (phps-mode/RETURN_TOKEN 'T_ECHO (match-beginning 0) (match-end 0)))
+   ((looking-at "print")
+    (phps-mode/RETURN_TOKEN 'T_PRINT (match-beginning 0) (match-end 0)))
+   ((looking-at "class")
+    (phps-mode/RETURN_TOKEN 'T_CLASS (match-beginning 0) (match-end 0)))
+   ((looking-at "interface")
+    (phps-mode/RETURN_TOKEN 'T_INTERFACE (match-beginning 0) (match-end 0)))
+   ((looking-at "trait")
+    (phps-mode/RETURN_TOKEN 'T_TRAIT (match-beginning 0) (match-end 0)))
+   ((looking-at "extends")
+    (phps-mode/RETURN_TOKEN 'T_EXTENDS (match-beginning 0) (match-end 0)))
+   ((looking-at "implements")
+    (phps-mode/RETURN_TOKEN 'T_IMPLEMENTS (match-beginning 0) (match-end 0)))
+
+   ((looking-at "->")
+    (phps-mode/yy_push_state phps-mode/ST_LOOKING_FOR_PROPERTY)
+    (phps-mode/RETURN_TOKEN 'T_OBJECT_OPERATOR (match-beginning 0) (match-end 
0)))
+
+   ((looking-at "\\?>\n?")
+    (let ((start (match-beginning 0))
+          (end (match-end 0)))
+      (phps-mode/BEGIN phps-mode/ST_INITIAL)
+      (when phps-mode/PARSER_MODE
+        (phps-mode/RETURN_TOKEN ";" start end))
+      (phps-mode/RETURN_TOKEN 'T_CLOSE_TAG start end)))
+
+   ;; HEREDOC and NOWDOC
+   ((looking-at (concat "<<<" phps-mode/TABS_AND_SPACES "\\(" phps-mode/LABEL 
"\\|'" phps-mode/LABEL "'\\|\"" phps-mode/LABEL "\"\\)" phps-mode/NEWLINE))
+    (let* ((start (match-beginning 0))
+           (end (match-end 0))
+           (data (buffer-substring (match-beginning 1) (match-end 1)))
+           (heredoc_label))
+
+      ;; Determine if it's HEREDOC or NOWDOC and extract label here
+      (if (string= (substring data 0 1) "'")
+          (progn
+            (setq heredoc_label (substring data 1 (- (length data) 1)))
+            (phps-mode/BEGIN phps-mode/ST_NOWDOC))
+        (progn
+          (if (string= (substring data 0 1) "\"")
+              (setq heredoc_label (substring data 1 (- (length data) 1)))
+            (setq heredoc_label data))
+          (phps-mode/BEGIN phps-mode/ST_HEREDOC)))
+
+      ;; Check for ending label on the next line
+      (when (string= (buffer-substring end (+ end (length heredoc_label))) 
heredoc_label)
+        (phps-mode/BEGIN phps-mode/ST_END_HEREDOC))
+
+      (push heredoc_label phps-mode/heredoc_label_stack)
+      ;; (message "Found heredoc or nowdoc at %s with label %s" data 
heredoc_label)
+
+      (phps-mode/RETURN_TOKEN 'T_START_HEREDOC start end)))
+
+   ((looking-at "::")
+      (phps-mode/RETURN_TOKEN 'T_PAAMAYIM_NEKUDOTAYIM (match-beginning 0) 
(match-end 0)))
+   ((looking-at "\\\\")
+    (phps-mode/RETURN_TOKEN 'T_NS_SEPARATOR (match-beginning 0) (match-end 0)))
+   ((looking-at "\\.\\.\\.")
+    (phps-mode/RETURN_TOKEN 'T_ELLIPSIS (match-beginning 0) (match-end 0)))
+   ((looking-at "\\?\\?")
+    (phps-mode/RETURN_TOKEN 'T_COALESCE (match-beginning 0) (match-end 0)))
+   ((looking-at "new")
+    (phps-mode/RETURN_TOKEN 'T_NEW (match-beginning 0) (match-end 0)))
+   ((looking-at "clone")
+    (phps-mode/RETURN_TOKEN 'T_CLONE (match-beginning 0) (match-end 0)))
+   ((looking-at "var")
+    (phps-mode/RETURN_TOKEN 'T_VAR (match-beginning 0) (match-end 0)))
+   ((looking-at (concat "(" phps-mode/TABS_AND_SPACES "\\(integer\\|int\\)" 
phps-mode/TABS_AND_SPACES ")"))
+    (phps-mode/RETURN_TOKEN 'T_INT_CAST (match-beginning 0) (match-end 0)))
+   ((looking-at (concat "(" phps-mode/TABS_AND_SPACES 
"\\(real\\|double\\|float\\)" phps-mode/TABS_AND_SPACES ")"))
+    (phps-mode/RETURN_TOKEN 'T_DOUBLE_CAST (match-beginning 0) (match-end 0)))
+   ((looking-at (concat "(" phps-mode/TABS_AND_SPACES "\\(string\\|binary\\)" 
phps-mode/TABS_AND_SPACES ")"))
+    (phps-mode/RETURN_TOKEN 'T_STRING_CAST (match-beginning 0) (match-end 0)))
+   ((looking-at (concat "(" phps-mode/TABS_AND_SPACES "array" 
phps-mode/TABS_AND_SPACES ")"))
+    (phps-mode/RETURN_TOKEN 'T_ARRAY_CAST (match-beginning 0) (match-end 0)))
+   ((looking-at (concat "(" phps-mode/TABS_AND_SPACES "object" 
phps-mode/TABS_AND_SPACES ")"))
+    (phps-mode/RETURN_TOKEN 'T_OBJECT_CAST (match-beginning 0) (match-end 0)))
+   ((looking-at (concat "(" phps-mode/TABS_AND_SPACES "\\(boolean\\|bool\\)" 
phps-mode/TABS_AND_SPACES ")"))
+    (phps-mode/RETURN_TOKEN 'T_BOOL_CAST (match-beginning 0) (match-end 0)))
+   ((looking-at (concat "(" phps-mode/TABS_AND_SPACES "unset" 
phps-mode/TABS_AND_SPACES ")"))
+    (phps-mode/RETURN_TOKEN 'T_UNSET_CAST (match-beginning 0) (match-end 0)))
+   ((looking-at "eval")
+    (phps-mode/RETURN_TOKEN 'T_EVAL (match-beginning 0) (match-end 0)))
+   ((looking-at "include_once")
+    (phps-mode/RETURN_TOKEN 'T_INCLUDE_ONCE (match-beginning 0) (match-end 0)))
+   ((looking-at "include")
+    (phps-mode/RETURN_TOKEN 'T_INCLUDE (match-beginning 0) (match-end 0)))
+   ((looking-at "require_once")
+    (phps-mode/RETURN_TOKEN 'T_REQUIRE_ONCE (match-beginning 0) (match-end 0)))
+   ((looking-at "require")
+    (phps-mode/RETURN_TOKEN 'T_REQUIRE (match-beginning 0) (match-end 0)))
+   ((looking-at "namespace")
+    (setq phps-mode/declaring_namespace t)
+    (phps-mode/RETURN_TOKEN 'T_NAMESPACE (match-beginning 0) (match-end 0)))
+   ((looking-at "use")
+    (phps-mode/RETURN_TOKEN 'T_USE (match-beginning 0) (match-end 0)))
+   ((looking-at "insteadof")
+    (phps-mode/RETURN_TOKEN 'T_INSTEADOF (match-beginning 0) (match-end 0)))
+   ((looking-at "global")
+    (phps-mode/RETURN_TOKEN 'T_GLOBAL (match-beginning 0) (match-end 0)))
+   ((looking-at "isset")
+    (phps-mode/RETURN_TOKEN 'T_ISSET (match-beginning 0) (match-end 0)))
+   ((looking-at "empty")
+    (phps-mode/RETURN_TOKEN 'T_EMPTY (match-beginning 0) (match-end 0)))
+   ((looking-at "__halt_compiler")
+    (phps-mode/RETURN_TOKEN 'T_HALT_COMPILER (match-beginning 0) (match-end 
0)))
+   ((looking-at "static")
+    (phps-mode/RETURN_TOKEN 'T_STATIC (match-beginning 0) (match-end 0)))
+   ((looking-at "abstract")
+    (phps-mode/RETURN_TOKEN 'T_ABSTRACT (match-beginning 0) (match-end 0)))
+   ((looking-at "final")
+    (phps-mode/RETURN_TOKEN 'T_FINAL (match-beginning 0) (match-end 0)))
+   ((looking-at "private")
+    (phps-mode/RETURN_TOKEN 'T_PRIVATE (match-beginning 0) (match-end 0)))
+   ((looking-at "protected")
+    (phps-mode/RETURN_TOKEN 'T_PROTECTED (match-beginning 0) (match-end 0)))
+   ((looking-at "public")
+    (phps-mode/RETURN_TOKEN 'T_PUBLIC (match-beginning 0) (match-end 0)))
+   ((looking-at "unset")
+    (phps-mode/RETURN_TOKEN 'T_UNSET (match-beginning 0) (match-end 0)))
+   ((looking-at "=>")
+    (phps-mode/RETURN_TOKEN 'T_DOUBLE_ARROW (match-beginning 0) (match-end 0)))
+   ((looking-at "list")
+    (phps-mode/RETURN_TOKEN 'T_LIST (match-beginning 0) (match-end 0)))
+   ((looking-at "array")
+    (phps-mode/RETURN_TOKEN 'T_ARRAY (match-beginning 0) (match-end 0)))
+   ((looking-at "callable")
+    (phps-mode/RETURN_TOKEN 'T_CALLABLE (match-beginning 0) (match-end 0)))
+   ((looking-at "\\+\\+")
+    (phps-mode/RETURN_TOKEN 'T_INC (match-beginning 0) (match-end 0)))
+   ((looking-at "--")
+    (phps-mode/RETURN_TOKEN 'T_DEC (match-beginning 0) (match-end 0)))
+   ((looking-at "===")
+    (phps-mode/RETURN_TOKEN 'T_IS_IDENTICAL (match-beginning 0) (match-end 0)))
+   ((looking-at "!==")
+    (phps-mode/RETURN_TOKEN 'T_IS_NOT_IDENTICAL (match-beginning 0) (match-end 
0)))
+   ((looking-at "==")
+    (phps-mode/RETURN_TOKEN 'T_IS_EQUAL (match-beginning 0) (match-end 0)))
+   ((looking-at "\\(!=\\|<>\\)")
+    (phps-mode/RETURN_TOKEN 'T_IS_NOT_EQUAL (match-beginning 0) (match-end 0)))
+   ((looking-at "<=>")
+    (phps-mode/RETURN_TOKEN 'T_SPACESHIP (match-beginning 0) (match-end 0)))
+   ((looking-at "<=")
+    (phps-mode/RETURN_TOKEN 'T_IS_SMALLER_OR_EQUAL (match-beginning 0) 
(match-end 0)))
+   ((looking-at ">=")
+    (phps-mode/RETURN_TOKEN 'T_IS_GREATER_OR_EQUAL (match-beginning 0) 
(match-end 0)))
+   ((looking-at "\\+=")
+    (phps-mode/RETURN_TOKEN 'T_PLUS_EQUAL (match-beginning 0) (match-end 0)))
+   ((looking-at "-=")
+    (phps-mode/RETURN_TOKEN 'T_MINUS_EQUAL (match-beginning 0) (match-end 0)))
+   ((looking-at "\\*=")
+    (phps-mode/RETURN_TOKEN 'T_MUL_EQUAL (match-beginning 0) (match-end 0)))
+   ((looking-at "\\*\\\\\\*=")
+    (phps-mode/RETURN_TOKEN 'T_POW_EQUAL (match-beginning 0) (match-end 0)))
+   ((looking-at "\\*\\\\\\*")
+    (phps-mode/RETURN_TOKEN 'T_POW (match-beginning 0) (match-end 0)))
+   ((looking-at "/=")
+    (phps-mode/RETURN_TOKEN 'T_DIV_EQUAL (match-beginning 0) (match-end 0)))
+   ((looking-at "\\.=")
+    (phps-mode/RETURN_TOKEN 'T_CONCAT_EQUAL (match-beginning 0) (match-end 0)))
+   ((looking-at "%=")
+    (phps-mode/RETURN_TOKEN 'T_MOD_EQUAL (match-beginning 0) (match-end 0)))
+   ((looking-at "<<=")
+    (phps-mode/RETURN_TOKEN 'T_SL_EQUAL (match-beginning 0) (match-end 0)))
+   ((looking-at ">>=")
+    (phps-mode/RETURN_TOKEN 'T_SR_EQUAL (match-beginning 0) (match-end 0)))
+   ((looking-at "&=")
+    (phps-mode/RETURN_TOKEN 'T_AND_EQUAL (match-beginning 0) (match-end 0)))
+   ((looking-at "|=")
+    (phps-mode/RETURN_TOKEN 'T_OR_EQUAL (match-beginning 0) (match-end 0)))
+   ((looking-at "\\^=")
+    (phps-mode/RETURN_TOKEN 'T_XOR_EQUAL (match-beginning 0) (match-end 0)))
+   ((looking-at "||")
+    (phps-mode/RETURN_TOKEN 'T_BOOLEAN_OR (match-beginning 0) (match-end 0)))
+   ((looking-at "&&")
+    (phps-mode/RETURN_TOKEN 'T_BOOLEAN_AND (match-beginning 0) (match-end 0)))
+   ((looking-at "XOR")
+    (phps-mode/RETURN_TOKEN 'T_LOGICAL_XOR (match-beginning 0) (match-end 0)))
+   ((looking-at "OR")
+    (phps-mode/RETURN_TOKEN 'T_LOGICAL_OR (match-beginning 0) (match-end 0)))
+   ((looking-at "AND")
+    (phps-mode/RETURN_TOKEN 'T_LOGICAL_AND (match-beginning 0) (match-end 0)))
+   ((looking-at "<<")
+    (phps-mode/RETURN_TOKEN 'T_SL (match-beginning 0) (match-end 0)))
+   ((looking-at ">>")
+    (phps-mode/RETURN_TOKEN 'T_SR (match-beginning 0) (match-end 0)))
+
+   ((looking-at "{")
+    (phps-mode/yy_push_state phps-mode/ST_IN_SCRIPTING)
+    (when phps-mode/declaring_namespace
+      (setq phps-mode/declaring_namespace nil))
+    (phps-mode/RETURN_TOKEN "{" (match-beginning 0) (match-end 0)))
+
+   ((looking-at "}")
+    (when phps-mode/state_stack
+      ;; (message "State stack %s" phps-mode/state_stack)
+      ;; (message "popping state from } %s" (length phps-mode/state_stack))
+      (phps-mode/yy_pop_state))
+    (phps-mode/RETURN_TOKEN "}" (match-beginning 0) (match-end 0)))
+
+   ((looking-at phps-mode/BNUM)
+    (let* ((start (match-beginning 0))
+           (end (match-end 0))
+           (data (buffer-substring (+ start 2) end))
+           (long-number (string-to-number data 2)))
+      ;; (message "Binary number %s from %s" long-number data)
+      (if (> long-number phps-mode/long-limit)
+          (phps-mode/RETURN_TOKEN 'T_DNUMBER start end)
+        (phps-mode/RETURN_TOKEN 'T_LNUMBER start end))))
+
+   ((looking-at phps-mode/HNUM)
+    (let* ((start (match-beginning 0))
+           (end (match-end 0))
+           (data (buffer-substring (+ start 2) end))
+           (long-number (string-to-number data 16)))
+      ;; (message "Hexadecimal number %s from %s" long-number data)
+      (if (> long-number phps-mode/long-limit)
+          (phps-mode/RETURN_TOKEN 'T_DNUMBER start end)
+        (phps-mode/RETURN_TOKEN 'T_LNUMBER start end))))
+
+   ((or (looking-at phps-mode/EXPONENT_DNUM)
+        (looking-at phps-mode/DNUM))
+    (let* ((start (match-beginning 0))
+           (end (match-end 0))
+           (data (buffer-substring start end)))
+      ;; (message "Exponent/double at: %s" data)
+      (phps-mode/RETURN_TOKEN 'T_DNUMBER start end)))
+
+   ((looking-at phps-mode/LNUM)
+    (let* ((start (match-beginning 0))
+           (end (match-end 0))
+           (data (string-to-number (buffer-substring start end))))
+      ;; (message "Long number: %d" data)
+      (if (> data phps-mode/long-limit)
+          (phps-mode/RETURN_TOKEN 'T_DNUMBER start end)
+        (phps-mode/RETURN_TOKEN 'T_LNUMBER start end))))
+
+   ((looking-at "__CLASS__")
+    (phps-mode/RETURN_TOKEN 'T_CLASS_C (match-beginning 0) (match-end 0)))
+   ((looking-at "__TRAIT__")
+    (phps-mode/RETURN_TOKEN 'T_TRAIT_C (match-beginning 0) (match-end 0)))
+   ((looking-at "__FUNCTION__")
+    (phps-mode/RETURN_TOKEN 'T_FUNC_C (match-beginning 0) (match-end 0)))
+   ((looking-at "__METHOD__")
+    (phps-mode/RETURN_TOKEN 'T_METHOD_C (match-beginning 0) (match-end 0)))
+   ((looking-at "__LINE__")
+    (phps-mode/RETURN_TOKEN 'T_LINE (match-beginning 0) (match-end 0)))
+   ((looking-at "__FILE__")
+    (phps-mode/RETURN_TOKEN 'T_FILE (match-beginning 0) (match-end 0)))
+   ((looking-at "__DIR__")
+    (phps-mode/RETURN_TOKEN 'T_DIR (match-beginning 0) (match-end 0)))
+   ((looking-at "__NAMESPACE__")
+    (phps-mode/RETURN_TOKEN 'T_NS_C (match-beginning 0) (match-end 0)))
+
+   ((looking-at "\\(//\\|#\\)")
+    (let* ((start (match-beginning 0))
+           (end (match-end 0))
+           (data (buffer-substring start end))
+           (line (buffer-substring (line-beginning-position) 
(line-end-position))))
+      (if (string-match "\\?>" line)
+          (progn
+            (phps-mode/RETURN_TOKEN 'T_COMMENT start (match-end 0))
+            )
+        (progn
+          ;; TODO Handle expecting values here
+          (phps-mode/RETURN_TOKEN 'T_COMMENT start (line-end-position))
+          ))))
+
+   ((looking-at (concat "/\\*\\*" phps-mode/WHITESPACE))
+    (let* ((start (match-beginning 0))
+           (end (match-end 0))
+           (data (buffer-substring start end)))
+      (let ((string-start (search-forward "*/" nil t))
+            position)
+        (if string-start
+            (setq position string-start)
+          (setq position (point-max)))
+        (phps-mode/RETURN_TOKEN 'T_DOC_COMMENT start position)
+        )))
+
+   ((looking-at "/\\*")
+    (let* ((start (match-beginning 0))
+           (end (match-end 0))
+           (data (buffer-substring start end)))
+      (let ((string-start (search-forward "*/" nil t))
+            position)
+        (if string-start
+            (setq position string-start)
+          (setq position (point-max)))
+        (phps-mode/RETURN_TOKEN 'T_COMMENT start position)
+        )))
+
+   ((looking-at (concat "\\$" phps-mode/LABEL))
+    (let ((start (match-beginning 0))
+          (end (match-end 0)))
+      (phps-mode/RETURN_TOKEN 'T_VARIABLE start end)))
+
+   ((looking-at phps-mode/TOKENS)
+    (let* ((start (match-beginning 0))
+           (end (match-end 0))
+           (data (buffer-substring start end))
+           (use-brace nil))
+      ;; (message "Found token '%s'" data)
+      (when phps-mode/declaring_namespace
+        (when (string= data ";")
+          (setq phps-mode/prepend_trailing_brace t)
+          ;; (message "Set flag prepend trailing brace")
+          (setq use-brace t)
+          )
+        (setq phps-mode/declaring_namespace nil))
+      (if use-brace
+          (phps-mode/RETURN_TOKEN "{" start end)
+        (phps-mode/RETURN_TOKEN data start end))))
+
+   ((looking-at "'")
+    (let* ((start (match-beginning 0))
+           (end (match-end 0))
+           (data (buffer-substring start end))
+           (found nil))
+      (forward-char)
+      (let ((string-start (search-forward-regexp "[^\\\\]'" nil t)))
+        (if string-start
+            (progn
+              ;; (message "Single quoted string %s" (buffer-substring start 
string-start))
+              (phps-mode/RETURN_TOKEN 'T_CONSTANT_ENCAPSED_STRING start (+ 
string-start 1)))
+          (progn
+            ;; Unclosed single quotes
+            ;; (message "Single quoted string never ends..")
+            (phps-mode/RETURN_TOKEN 'T_ENCAPSED_AND_WHITESPACE start 
(point-max))
+            )))))
+
+   ;; Double quoted string
+   ((looking-at "\"")
+    (let* ((start (match-beginning 0))
+           (end (match-end 0))
+           (data (buffer-substring start end)))
+      (forward-char)
+      (let ((string-start (search-forward-regexp (concat
+                                                  "\\([^\\\\]\""
+                                                  "\\|\\$" phps-mode/LABEL
+                                                  "\\|\\${" phps-mode/LABEL
+                                                  "\\|{\\$" phps-mode/LABEL 
"\\)")
+                                                 nil t)))
+        ;; Do we find a ending double quote or starting variable?
+        (if string-start
+            (let ((string-start (match-beginning 0)))
+              ;; (message "Double quoted string %s" double-quoted-string)
+              ;; Do we find variable inside quote?
+              (goto-char string-start)
+              (if (looking-at "[^\\\\]\"")
+                  (progn
+                    (let ((double-quoted-string (buffer-substring start (+ 
string-start 2))))
+                      ;; (message "Double quoted string: %s" 
double-quoted-string)
+                      (phps-mode/RETURN_TOKEN 'T_CONSTANT_ENCAPSED_STRING 
start (+ string-start 2))))
+                  (progn
+                    ;; (message "Found variable after '%s'" (buffer-substring 
start (point)))
+                    (phps-mode/BEGIN phps-mode/ST_DOUBLE_QUOTES)
+                    (phps-mode/RETURN_TOKEN "\"" start (+ start 1))
+                    (phps-mode/RETURN_TOKEN 'T_ENCAPSED_AND_WHITESPACE (+ 
start 1) string-start)
+                    )
+                ))
+          (progn
+            ;; (message "Found no ending quote, skipping to end")
+            (phps-mode/RETURN_TOKEN 'T_ERROR start (point-max))
+            )))))
+
+   ((looking-at "[`]")
+    ;; (message "Begun backquote at %s-%s" (match-beginning 0) (match-end 0))
+    (phps-mode/BEGIN phps-mode/ST_BACKQUOTE)
+    (phps-mode/RETURN_TOKEN "`" (match-beginning 0) (match-end 0)))
+
+   ((looking-at phps-mode/WHITESPACE)
+    (let* ((start (match-beginning 0))
+           (end (match-end 0))
+           (data (buffer-substring start end)))
+      (if phps-mode/PARSER_MODE
+          (phps-mode/MOVE_FORWARD end)
+        (phps-mode/RETURN_TOKEN data start end))))
+
+   ((looking-at phps-mode/LABEL)
+    (phps-mode/RETURN_TOKEN 'T_STRING (match-beginning 0) (match-end 0)))
+
+   ((looking-at phps-mode/ANY_CHAR)
+    ;; Unexpected character
+    (phps-mode/RETURN_TOKEN 'T_ERROR (match-beginning 0) (point-max)))
+
+   ))
+
+(define-lex-analyzer phps-mode/lex--ST_LOOKING_FOR_PROPERTY "
+{WHITESPACE}+
+->
+{LABEL}
+{ANY_CHAR}
+"
+  (= phps-mode/STATE phps-mode/ST_LOOKING_FOR_PROPERTY)
+
+  (cond
+
+   ((looking-at phps-mode/WHITESPACE)
+    (let* ((start (match-beginning 0))
+           (end (match-end 0))
+           (data (buffer-substring start end)))
+      (if phps-mode/PARSER_MODE
+          (phps-mode/MOVE_FORWARD end)
+        (phps-mode/RETURN_TOKEN 'T_WHITESPACE start end))
+      ))
+
+   ((looking-at "->")
+    (phps-mode/RETURN_TOKEN 'T_OBJECT_OPERATOR (match-beginning 0) (match-end 
0)))
+
+   ((looking-at phps-mode/LABEL)
+    (let ((start (match-beginning 0))
+           (end (match-end 0)))
+      (phps-mode/yy_pop_state)
+      (phps-mode/RETURN_TOKEN 'T_STRING start end)
+      ))
+
+   ((looking-at phps-mode/ANY_CHAR)
+    (let ((start (match-beginning 0))
+          (end (match-end 0)))
+      (phps-mode/yy_pop_state)
+      ;; TODO goto restart here?
+      (message "Restart here")
+      (phps-mode/MOVE_FORWARD end)
+      ))
+
+   ))
+
+(define-lex-analyzer phps-mode/lex--ST_DOUBLE_QUOTES "
+<ST_DOUBLE_QUOTES>
+\"${\"
+\"$\"{LABEL}\"->\"[a-zA-Z_\x80-\xff]
+\"$\"{LABEL}\"[\"
+\"$\"{LABEL}
+\"{$\"
+[\"]
+{ANY_CHAR}
+"
+  (= phps-mode/STATE phps-mode/ST_DOUBLE_QUOTES)
+  (cond
+
+   ((looking-at "\\${")
+    (phps-mode/yy_push_state phps-mode/ST_LOOKING_FOR_VARNAME)
+    (phps-mode/RETURN_TOKEN 'T_DOLLAR_OPEN_CURLY_BRACES (match-beginning 0) 
(match-end 0)))
+
+   ((looking-at (concat "\\$" phps-mode/LABEL "->" "[a-zA-Z_\x80-\xff]"))
+    (phps-mode/yy_push_state phps-mode/ST_LOOKING_FOR_PROPERTY)
+    (phps-mode/RETURN_TOKEN 'T_VARIABLE (match-beginning 0) (match-end 0)))
+
+   ((looking-at (concat "\\$" phps-mode/LABEL "\\["))
+    (phps-mode/yy_push_state phps-mode/ST_VAR_OFFSET)
+    (phps-mode/RETURN_TOKEN 'T_VARIABLE (match-beginning 0) (match-end 0)))
+
+   ((looking-at (concat "\\$" phps-mode/LABEL))
+    (phps-mode/RETURN_TOKEN 'T_VARIABLE (match-beginning 0) (match-end 0)))
+
+   ((looking-at "{\\$")
+    (phps-mode/yy_push_state phps-mode/ST_IN_SCRIPTING)
+    (phps-mode/RETURN_TOKEN 'T_CURLY_OPEN (match-beginning 0) (- (match-end 0) 
1)))
+
+   ((looking-at "[\"]")
+    (phps-mode/BEGIN phps-mode/ST_IN_SCRIPTING)
+    ;; (message "Ended double-quote at %s" (match-beginning 0))
+    (phps-mode/RETURN_TOKEN "\"" (match-beginning 0) (match-end 0)))
+
+   ((looking-at phps-mode/ANY_CHAR)
+    (let ((start (point)))
+      (let ((string-start (search-forward-regexp "[^\\\\]\"" nil t)))
+        (if string-start
+            (let* ((end (- (match-end 0) 1))
+                   (double-quoted-string (buffer-substring start end)))
+              ;; Do we find variable inside quote?
+              (if (or (string-match (concat "\\$" phps-mode/LABEL) 
double-quoted-string)
+                      (string-match (concat "\\${" phps-mode/LABEL) 
double-quoted-string)
+                      (string-match (concat "{\\$" phps-mode/LABEL) 
double-quoted-string))
+                  (progn
+                    (let ((variable-start (+ start (match-beginning 0))))
+                      (phps-mode/RETURN_TOKEN 'T_CONSTANT_ENCAPSED_STRING 
start variable-start)
+                    ))
+                (progn
+                  (phps-mode/RETURN_TOKEN 'T_CONSTANT_ENCAPSED_STRING start 
end)
+                  ;; (message "Found end of quote at %s-%s, moving ahead after 
'%s'" start end (buffer-substring start end))
+                  )))
+          (progn
+            ;; "Found no end of double-quoted region
+            (phps-mode/RETURN_TOKEN 'T_ERROR start (point-max)))))))
+
+   ))
+
+(define-lex-analyzer phps-mode/lex--ST_BACKQUOTE "
+\"{$\"
+\"$\"{LABEL}\"->\"[a-zA-Z_\x80-\xff]
+\"$\"{LABEL}\"[\"
+\"$\"{LABEL}
+{$
+`
+ANY_CHAR'
+"
+  (= phps-mode/STATE phps-mode/ST_BACKQUOTE)
+  (let ((old-start (point)))
+        (cond
+
+         ((looking-at "\\${")
+          (phps-mode/yy_push_state phps-mode/ST_LOOKING_FOR_VARNAME)
+          (phps-mode/RETURN_TOKEN 'T_DOLLAR_OPEN_CURLY_BRACES (match-beginning 
0) (match-end 0)))
+
+         ((looking-at (concat "\\$" phps-mode/LABEL "->" "[a-zA-Z_\x80-\xff]"))
+          (phps-mode/yy_push_state phps-mode/ST_LOOKING_FOR_PROPERTY)
+          (phps-mode/RETURN_TOKEN 'T_VARIABLE (match-beginning 0) (match-end 
0)))
+
+         ((looking-at (concat "\\$" phps-mode/LABEL "\\["))
+          (phps-mode/yy_push_state phps-mode/ST_VAR_OFFSET)
+          (phps-mode/RETURN_TOKEN 'T_VARIABLE (match-beginning 0) (match-end 
0)))
+
+         ((looking-at (concat "\\$" phps-mode/LABEL))
+          (phps-mode/RETURN_TOKEN 'T_VARIABLE (match-beginning 0) (match-end 
0)))
+
+         ((looking-at "{\\$")
+          (phps-mode/yy_push_state phps-mode/ST_IN_SCRIPTING)
+          (phps-mode/RETURN_TOKEN 'T_CURLY_OPEN (match-beginning 0) (- 
(match-end 0) 1)))
+
+         ((looking-at "[`]")
+          (phps-mode/BEGIN phps-mode/ST_IN_SCRIPTING)
+          (phps-mode/RETURN_TOKEN "`" (match-beginning 0) (match-end 0)))
+
+         ((looking-at phps-mode/ANY_CHAR)
+          (let ((string-start (search-forward-regexp 
"\\([^\\\\]`\\|\\$\\|{\\)" nil t)))
+            (if string-start
+                (let ((start (- (match-end 0) 1)))
+                  ;; (message "Skipping backquote forward over %s" 
(buffer-substring old-start start))
+                  (phps-mode/RETURN_TOKEN 'T_CONSTANT_ENCAPSED_STRING 
old-start start)
+                  )
+              (progn
+                ;; (message "Found no end of backquote.. skipping to end from 
%s" (buffer-substring (point) (point-max)))
+                (phps-mode/RETURN_TOKEN 'T_ERROR old-start (point-max))))))
+
+         )))
+
+(define-lex-analyzer phps-mode/lex--ST_HEREDOC "
+\"{$\"
+\"$\"{LABEL}\"->\"[a-zA-Z_\x80-\xff]
+\"$\"{LABEL}\"[\"
+\"$\"{LABEL}
+{$
+`
+ANY_CHAR'
+"
+  (= phps-mode/STATE phps-mode/ST_HEREDOC)
+
+  (let ((heredoc_label (car phps-mode/heredoc_label_stack))
+        (old-start (point)))
+    (cond
+
+     ((looking-at "\\${")
+      (phps-mode/yy_push_state phps-mode/ST_LOOKING_FOR_VARNAME)
+      (phps-mode/RETURN_TOKEN 'T_DOLLAR_OPEN_CURLY_BRACES (match-beginning 0) 
(match-end 0)))
+
+     ((looking-at (concat "\\$" phps-mode/LABEL "->" "[a-zA-Z_\x80-\xff]"))
+      (phps-mode/yy_push_state phps-mode/ST_LOOKING_FOR_PROPERTY)
+      (phps-mode/RETURN_TOKEN 'T_VARIABLE (match-beginning 0) (match-end 0)))
+
+     ((looking-at (concat "\\$" phps-mode/LABEL "\\["))
+      (phps-mode/yy_push_state phps-mode/ST_VAR_OFFSET)
+      (phps-mode/RETURN_TOKEN 'T_VARIABLE (match-beginning 0) (match-end 0)))
+
+     ((looking-at (concat "\\$" phps-mode/LABEL))
+      (phps-mode/RETURN_TOKEN 'T_VARIABLE (match-beginning 0) (match-end 0)))
+
+     ((looking-at (concat "{\\$"))
+      (phps-mode/yy_push_state phps-mode/ST_IN_SCRIPTING)
+      (phps-mode/RETURN_TOKEN 'T_CURLY_OPEN (match-beginning 0) (- (match-end 
0) 1)))
+
+     ((looking-at phps-mode/ANY_CHAR)
+      ;; (message "Found nothing useful at '%s' looking at {$ %s" 
(buffer-substring (point) (point-max)) (looking-at "{\\$"))
+      ;; Check for $, ${ and {$ forward
+      (let ((string-start (search-forward-regexp (concat "\\(\n" heredoc_label 
";?\n\\|\\$" phps-mode/LABEL "\\|{\\$" phps-mode/LABEL "\\|\\${" 
phps-mode/LABEL "\\)") nil t)))
+        (if string-start
+            (let* ((start (match-beginning 0))
+                   (end (match-end 0))
+                   (data (buffer-substring start end)))
+              ;; (message "Found something ending at %s" data)
+
+              (cond
+
+               ((string-match (concat "\n" heredoc_label ";?\n") data)
+                ;, (message "Found heredoc end at %s-%s" start end)
+                (phps-mode/BEGIN phps-mode/ST_END_HEREDOC)
+                (phps-mode/RETURN_TOKEN 'T_ENCAPSED_AND_WHITESPACE old-start 
start))
+
+               (t
+                ;; (message "Found variable at '%s'.. Skipping forward to %s" 
data start)
+                (phps-mode/RETURN_TOKEN 'T_ENCAPSED_AND_WHITESPACE old-start 
start)
+                )
+
+               ))
+          (progn
+            ;; (message "Found no ending of heredoc at %s '%s'" heredoc_label 
(buffer-substring (point) (point-max)))
+            (phps-mode/RETURN_TOKEN 'T_ERROR old-start (point-max))
+            ))))
+
+     )))
+
+(define-lex-analyzer phps-mode/lex--ST_NOWDOC "
+ANY_CHAR'
+"
+  (= phps-mode/STATE phps-mode/ST_NOWDOC)
+
+  (let ((heredoc_label (car phps-mode/heredoc_label_stack))
+        (old-start (point)))
+    (cond
+
+     ((looking-at phps-mode/ANY_CHAR)
+      (let ((string-start (search-forward-regexp (concat "\n" heredoc_label 
";?\n") nil t)))
+        (if string-start
+            (let* ((start (match-beginning 0))
+                   (end (match-end 0))
+                   (data (buffer-substring start end)))
+              ;; (message "Found something ending at %s" data)
+              ;; (message "Found nowdoc end at %s-%s" start end)
+              (phps-mode/BEGIN phps-mode/ST_END_HEREDOC)
+              (phps-mode/RETURN_TOKEN 'T_ENCAPSED_AND_WHITESPACE old-start 
start)
+              )
+          (progn
+            ;; (message "Found no ending of nowdoc at %s '%s'" heredoc_label 
(buffer-substring (point) (point-max)))
+            (phps-mode/RETURN_TOKEN 'T_ERROR old-start (point-max))
+            ))))
+     )))
+
+(define-lex-analyzer phps-mode/lex--ST_LOOKING_FOR_VARNAME "
+{LABEL}[[}]
+{ANY_CHAR}"
+  (= phps-mode/STATE phps-mode/ST_LOOKING_FOR_VARNAME)
+  (cond
+
+   ((looking-at (concat phps-mode/LABEL "[\\[}]"))
+    (let ((start (match-beginning 0))
+           (end (- (match-end 0) 1)))
+      (phps-mode/yy_pop_state)
+      (phps-mode/yy_push_state phps-mode/ST_IN_SCRIPTING)
+      (phps-mode/RETURN_TOKEN 'T_STRING_VARNAME start end)))
+
+   ((looking-at phps-mode/ANY_CHAR)
+    (phps-mode/yy_pop_state)
+    (phps-mode/yy_push_state phps-mode/ST_IN_SCRIPTING))
+
+   ))
+
+(define-lex-analyzer phps-mode/lex--ST_END_HEREDOC "
+{ANY_CHAR}"
+  (= phps-mode/STATE phps-mode/ST_END_HEREDOC)
+  (let ((heredoc_label (car phps-mode/heredoc_label_stack)))
+    (cond
+
+     ((looking-at (concat phps-mode/ANY_CHAR))
+
+      (let* ((start (match-beginning 0))
+             (end (+ start (length heredoc_label) 1))
+             (data (buffer-substring start end)))
+        ;; (message "Found ending heredoc at %s, %s of %s" data 
(thing-at-point 'line) heredoc_label)
+        (pop phps-mode/heredoc_label_stack)
+        (phps-mode/BEGIN phps-mode/ST_IN_SCRIPTING)
+        (phps-mode/RETURN_TOKEN 'T_END_HEREDOC start end)
+
+      ))
+
+     )))
+
+(define-lex-analyzer phps-mode/lex--ST_VAR_OFFSET "
+[0]|([1-9][0-9]*)
+{LNUM}|{HNUM}|{BNUM}
+\"$\"{LABEL}
+]
+{TOKENS}|[{}\"`]
+[ \n\r\t\\'#]
+{LABEL}
+{ANY_CHAR}
+"
+  (= phps-mode/STATE phps-mode/ST_VAR_OFFSET)
+
+  (cond
+
+   ((looking-at (concat "\\("
+                        phps-mode/LNUM "\\|"
+                        phps-mode/HNUM "\\|"
+                        phps-mode/BNUM "\\)"))
+    (phps-mode/RETURN_TOKEN 'T_NUM_STRING (match-beginning 0) (match-end 0)))
+
+   ((looking-at (concat "\\$" phps-mode/LABEL))
+    (phps-mode/RETURN_TOKEN 'T_VARIABLE (match-beginning 0) (match-end 0)))
+
+   ((looking-at "\\]")
+    (phps-mode/yy_pop_state)
+    (phps-mode/RETURN_TOKEN "]" (match-beginning 0) (match-end 0)))
+
+   ((looking-at (concat "\\(" phps-mode/TOKENS
+                        "\\|[{}\"`]\\)"))
+    (let* ((start (match-beginning 0))
+           (end (match-end 0))
+           (data (buffer-substring start end)))
+      (phps-mode/RETURN_TOKEN data start end)))
+
+   ((looking-at (concat "[ \n\r\t'#]"))
+    (let* ((start (match-beginning 0))
+           (end (- (match-end 0) 1)))
+      (phps-mode/yy_pop_state)
+      (phps-mode/RETURN_TOKEN 'T_ENCAPSED_AND_WHITESPACE start end)))
+
+   ((looking-at phps-mode/LABEL)
+    (phps-mode/RETURN_TOKEN 'T_STRING (match-beginning 0) (match-end 0)))
+
+   ((looking-at phps-mode/ANY_CHAR)
+    ;; Unexpected character
+    (phps-mode/RETURN_TOKEN 'T_ERROR (match-beginning 0) (point-max)))
+
+   ))
+
+
+(define-lex phps-mode/tags-lexer
+  "Lexer that handles PHP buffers."
+
+  phps-mode/lex--INITIAL
+  phps-mode/lex--ST_IN_SCRIPTING
+  phps-mode/lex--ST_LOOKING_FOR_PROPERTY
+  phps-mode/lex--ST_DOUBLE_QUOTES
+  phps-mode/lex--ST_BACKQUOTE
+  phps-mode/lex--ST_HEREDOC
+  phps-mode/lex--ST_NOWDOC
+  phps-mode/lex--ST_LOOKING_FOR_VARNAME
+  phps-mode/lex--ST_END_HEREDOC
+  phps-mode/lex--ST_VAR_OFFSET
+
+  semantic-lex-default-action)
+
+(defun phps-mode/lexer-init ()
+  "Initialize lexer."
+
+  (let ((phps-mode-syntax-table (make-syntax-table)))
+
+    ;; This is added so entity names with underscores can be more easily 
parsed as one word
+    (modify-syntax-entry ?_ "w" phps-mode-syntax-table)
+
+    ;; Comment styles are same as C++
+    (modify-syntax-entry ?/ ". 124b"  phps-mode-syntax-table)
+    (modify-syntax-entry ?* ". 23" phps-mode-syntax-table)
+    (modify-syntax-entry ?\n "> b" phps-mode-syntax-table)
+
+    (setq semantic-lex-syntax-table phps-mode-syntax-table))
+
+  (phps-mode/BEGIN phps-mode/ST_INITIAL)
+
+  (setq
+
+   ;; Syntax table modifications
+   ;; TODO Understand this
+   ;; semantic-lex-syntax-modifications
+   ;; '(
+   ;;   (?= ".")
+   ;;   (?& ".")
+   ;;   (?+ ".")
+   ;;   (?- ".")
+   ;;   (?| ".")
+   ;;   (?< ".")
+   ;;   (?> ".")
+   ;;   (?% ".")
+   ;;   (?' "\"")
+   ;;   (?\" "\"")
+   ;;   (?` "\"")
+   ;;   (?_ "w")
+   ;;   (?$ "_")
+   ;;   (?/ ". 124b")
+   ;;   (?* ". 23")
+   ;;   (?\n "> b")
+   ;;   (?# "< b"))
+
+   ;; Lexical analysis
+   semantic-lex-analyzer 'phps-mode/tags-lexer
+
+   )
+
+  (semantic-lex-buffer)
+
+  )
+
+(provide 'phps-mode/lexer)
+
+;;; phps-lexer.el ends here
diff --git a/phps-map.el b/phps-map.el
new file mode 100644
index 0000000..12320a6
--- /dev/null
+++ b/phps-map.el
@@ -0,0 +1,49 @@
+;; phps-mode/phps-map.el --- Map for major mode
+
+;; Author: Christian Johansson <github.com/cjohansson>
+;; Maintainer: Christian Johansson <github.com/cjohansson>
+;; Created: 3 Mar 2018
+;; Modified: .
+;; Version: 0.1
+;; Keywords: tools, convenience
+;; URL: -
+
+;; Copyright (C) 2017 Christian Johansson
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; 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.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Spathoftware Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+
+;;; Commentary:
+
+;; Please see README.md from the same repository for extended documentation.
+
+;;; Code:
+
+
+(defvar phps-mode/map
+  (let ((map (make-keymap)))
+    ;; TODO keys here
+    map)
+  "Key-map for major mode.")
+
+(defun phps-mode/map-init ()
+  "Apply map to mode."
+  (use-local-map phps-mode/map))
+
+(provide 'phps-mode/map)
+;;; phps-map.el ends here
diff --git a/phps-mode.el b/phps-mode.el
new file mode 100644
index 0000000..65542f7
--- /dev/null
+++ b/phps-mode.el
@@ -0,0 +1,94 @@
+;;; phps-mode.el --- Major mode for PHP with Semantic integration
+
+;; Author: Christian Johansson <github.com/cjohansson>
+;; Maintainer: Christian Johansson <github.com/cjohansson>
+;; Created: 3 Mar 2018
+;; Modified: .
+;; Version: 0.1
+;; Keywords: tools, convenience
+;; URL: -
+
+;; Package-Requires: ((emacs "24"))
+
+;; Copyright (C) 2017 Christian Johansson
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; 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.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Spathoftware Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+
+;;; Commentary:
+
+;; Please see README.md from the same repository for extended documentation.
+
+;; TODO 0. Add tests for semantic like semantic-php project
+;; TODO 1. Get semantic working based on zend_language_parser.y
+;; TODO 2. Add support for flymake
+;; DONE 3. Add support for flycheck
+;; TODO 4. Get syntax coloring working based on semantic data (as js2-mode)
+;; TODO 5. Get indent-functions working
+
+;; NOTE use wisent-parse-toggle-verbose-flag and (semantic-debug) to debug 
parsing
+
+
+;;; Code:
+
+
+(autoload 'phps-mode/flycheck-init "phps-flycheck")
+(autoload 'phps-mode/flymake-init "phps-flymake")
+(autoload 'phps-mode/font-lock-init "phps-font-lock")
+(autoload 'phps-mode/functions-init "phps-functions")
+(autoload 'phps-mode/map-init "phps-map")
+(autoload 'phps-mode/lexer-init "phps-lexer")
+(autoload 'phps-mode/syntax-table-init "phps-syntax-table")
+(autoload 'phps-mode/tags-init "phps-tags")
+(autoload 'phps-mode/semantic-init "phps-semantic")
+
+(define-derived-mode phps-mode prog-mode "PHPs"
+  "Major mode for PHP with Semantic integration."
+
+  ;; Key-map
+  (phps-mode/map-init)
+
+  ;; Syntax table
+  (phps-mode/syntax-table-init)
+
+  ;; Font lock
+  (phps-mode/font-lock-init)
+
+  ;; Flymake
+  ;; (phps-mode/flymake-init)
+
+  ;; Flycheck
+  (phps-mode/flycheck-init)
+
+  ;; Override functions
+  (phps-mode/functions-init)
+
+  (setq major-mode 'phps-mode)
+  (setq mode-name "PHPs")
+
+  ;; Lexer
+  (phps-mode/lexer-init)
+
+  ;; Wisent LALR parser
+  ;; (phps-mode/tags-init)
+
+  (run-hooks 'phps-mode-hook)
+  (semantic-new-buffer-fcn))
+
+(provide 'phps-mode)
+;;; phps-mode.el ends here
diff --git a/phps-semantic.el b/phps-semantic.el
new file mode 100644
index 0000000..0f6d4ac
--- /dev/null
+++ b/phps-semantic.el
@@ -0,0 +1,489 @@
+;;; phps-mode/phps-semantic.el --- Semantic functions for PHP
+
+;;; Copyright (C) 1999-2018 Free Software Foundation, Inc.
+
+;; Author: David Ponce <address@hidden>
+
+;; This file is not part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs 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.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Make similar to 
/Users/christianjohansson/Documents/emacs/nextstep/Emacs.app/Contents/Resources/lisp/cedet/semantic/java.el.gz
+;;
+;; Common function for PHP parsers.
+
+;;; Code:
+(require 'semantic)
+(require 'semantic/ctxt)
+(require 'semantic/doc)
+(require 'semantic/format)
+
+(eval-when-compile
+  (require 'semantic/find)
+  (require 'semantic/dep))
+
+;;; Lexical analysis
+;; TODO Verify this syntax
+(defconst semantic-php-number-regexp
+  (eval-when-compile
+    (concat "\\("
+            "\\<[0-9]+[.][0-9]+\\([eE][-+]?[0-9]+\\)?[fFdD]?\\>"
+            "\\|"
+            "\\<[0-9]+[.][eE][-+]?[0-9]+[fFdD]?\\>"
+            "\\|"
+            "\\<[0-9]+[.][fFdD]\\>"
+            "\\|"
+            "\\<[0-9]+[.]"
+            "\\|"
+            "[.][0-9]+\\([eE][-+]?[0-9]+\\)?[fFdD]?\\>"
+            "\\|"
+            "\\<[0-9]+[eE][-+]?[0-9]+[fFdD]?\\>"
+            "\\|"
+            "\\<0[xX][0-9a-fA-F]+[lL]?\\>"
+            "\\|"
+            "\\<[0-9]+[lLfFdD]?\\>"
+            "\\)"
+            ))
+  "Lexer regexp to match PHP number terminals.
+Following is the specification of PHP number literals.
+
+DECIMAL_LITERAL:
+    [1-9][0-9]*
+  ;
+HEX_LITERAL:
+    0[xX][0-9a-fA-F]+
+  ;
+OCTAL_LITERAL:
+    0[0-7]*
+  ;
+INTEGER_LITERAL:
+    <DECIMAL_LITERAL>[lL]?
+  | <HEX_LITERAL>[lL]?
+  | <OCTAL_LITERAL>[lL]?
+  ;
+EXPONENT:
+    [eE][+-]?[09]+
+  ;
+FLOATING_POINT_LITERAL:
+    [0-9]+[.][0-9]*<EXPONENT>?[fFdD]?
+  | [.][0-9]+<EXPONENT>?[fFdD]?
+  | [0-9]+<EXPONENT>[fFdD]?
+  | [0-9]+<EXPONENT>?[fFdD]
+  ;")
+
+;;; Parsing
+
+;; TODO Verify this
+(defsubst semantic-php-dim (id)
+  "Split ID string into a pair (NAME . DIM).
+NAME is ID without trailing brackets: \"[]\".
+DIM is the dimension of NAME deduced from the number of trailing
+brackets, or 0 if there is no trailing brackets."
+  (let ((dim (string-match "\\(\\[]\\)+\\'" id)))
+    (if dim
+        (cons (substring id 0 dim)
+              (/ (length (match-string 0 id)) 2))
+      (cons id 0))))
+
+;; TODO Verify this
+(defsubst semantic-php-type (tag)
+  "Return the type of TAG, taking care of array notation."
+  (let ((type (semantic-tag-type tag))
+        (dim  (semantic-tag-get-attribute tag :dereference)))
+    (when dim
+      (while (> dim 0)
+        (setq type (concat type "[]")
+              dim (1- dim))))
+    type))
+
+;; TODO Verify this, how about ::?
+(defun semantic-php-expand-tag (tag)
+  "Expand compound declarations found in TAG into separate tags.
+TAG contains compound declarations when its class is `variable', and
+its name is a list of elements (NAME START . END), where NAME is a
+compound variable name, and START/END are the bounds of the
+corresponding compound declaration."
+  (let* ((class (semantic-tag-class tag))
+         (elts (semantic-tag-name tag))
+         dim type dim0 elt clone start end xpand)
+    (cond
+     ((and (eq class 'function)
+           (> (cdr (setq dim (semantic-php-dim elts))) 0))
+      (setq clone (semantic-tag-clone tag (car dim))
+            xpand (cons clone xpand))
+      (semantic-tag-put-attribute clone :dereference (cdr dim)))
+
+     ((eq class 'variable)
+      (or (consp elts) (setq elts (list (list elts))))
+      (setq dim  (semantic-php-dim (semantic-tag-get-attribute tag :type))
+            type (car dim)
+            dim0 (cdr dim))
+      (while elts
+        ;; For each compound element, clone the initial tag with the
+        ;; name and bounds of the compound variable declaration.
+        (setq elt   (car elts)
+              elts  (cdr elts)
+              start (if elts  (cadr elt) (semantic-tag-start tag))
+              end   (if xpand (cddr elt) (semantic-tag-end   tag))
+              dim   (semantic-php-dim (car elt))
+              clone (semantic-tag-clone tag (car dim))
+              xpand (cons clone xpand))
+        (semantic-tag-put-attribute clone :type type)
+        (semantic-tag-put-attribute clone :dereference (+ dim0 (cdr dim)))
+        (semantic-tag-set-bounds clone start end)))
+
+     ((and (eq class 'type) (string-match "\\->" (semantic-tag-name tag)))
+      ;; phpp outputs files where the package name is stuck onto the class or 
interface
+      ;; name.  To make this more regular, we extract the package name into a 
package statement,
+      ;; then make the class name regular.
+      (let* ((name (semantic-tag-name tag))
+             (rsplit (nreverse (split-string name "\\->" t)))
+             (newclassname (car rsplit))
+             (newpkg (mapconcat 'identity (reverse (cdr rsplit)) "->")))
+        (semantic-tag-set-name tag newclassname)
+        (setq xpand
+              (list tag
+                    (semantic-tag-new-package newpkg nil))))
+      ))
+    xpand))
+
+;;; Environment
+;; TODO Verify this
+(defcustom-mode-local-semantic-dependency-system-include-path
+  phps-mode semantic-php-dependency-system-include-path
+  ;; @todo - Use JDEE to get at the include path, or something else?
+  nil
+  "The system include path used by PHP language.")
+
+;; Local context
+;; TODO Verify this
+(define-mode-local-override semantic-ctxt-scoped-types
+  phps-mode (&optional point)
+  "Return a list of type names currently in scope at POINT."
+  (mapcar 'semantic-tag-name
+          (semantic-find-tags-by-class
+           'type (semantic-find-tag-by-overlay point))))
+
+;; Tag Protection
+;; TODO Verify this
+(define-mode-local-override semantic-tag-protection
+  phps-mode (tag &optional parent)
+  "Return the protection of TAG in PARENT.
+Override function for `semantic-tag-protection'."
+  (let ((prot (semantic-tag-protection-default tag parent)))
+    (or prot 'package)))
+
+;; Prototype handler
+;;
+(defun semantic-php-prototype-function (tag &optional parent color)
+  "Return a function (method) prototype for TAG.
+Optional argument PARENT is a parent (containing) item.
+Optional argument COLOR indicates that color should be mixed in.
+See also `semantic-format-tag-prototype'."
+  (let ((name (semantic-tag-name tag))
+        (type (semantic-php-type tag))
+        (tmpl (semantic-tag-get-attribute tag :template-specifier))
+        (args (semantic-tag-function-arguments tag))
+        (argp "")
+        arg argt)
+    (while args
+      (setq arg  (car args)
+            args (cdr args))
+      (if (semantic-tag-p arg)
+          (setq argt (if color
+                         (semantic--format-colorize-text
+                          (semantic-php-type arg) 'type)
+                       (semantic-php-type arg))
+                argp (concat argp argt (if args "," "")))))
+    (when color
+      (when type
+        (setq type (semantic--format-colorize-text type 'type)))
+      (setq name (semantic--format-colorize-text name 'function)))
+    (concat (or tmpl "") (if tmpl " " "")
+            (or type "") (if type " " "")
+            name "(" argp ")")))
+
+(defun semantic-php-prototype-variable (tag &optional parent color)
+  "Return a variable (field) prototype for TAG.
+Optional argument PARENT is a parent (containing) item.
+Optional argument COLOR indicates that color should be mixed in.
+See also `semantic-format-tag-prototype'."
+  (let ((name (semantic-tag-name tag))
+        (type (semantic-php-type tag)))
+    (concat (if color
+                (semantic--format-colorize-text type 'type)
+              type)
+            " "
+            (if color
+                (semantic--format-colorize-text name 'variable)
+              name))))
+
+(defun semantic-php-prototype-type (tag &optional parent color)
+  "Return a type (class/interface) prototype for TAG.
+Optional argument PARENT is a parent (containing) item.
+Optional argument COLOR indicates that color should be mixed in.
+See also `semantic-format-tag-prototype'."
+  (let ((name (semantic-tag-name tag))
+        (type (semantic-tag-type tag))
+        (tmpl (semantic-tag-get-attribute tag :template-specifier)))
+    (concat type " "
+            (if color
+                (semantic--format-colorize-text name 'type)
+              name)
+            (or tmpl ""))))
+
+;; TODO Verify this
+(define-mode-local-override semantic-format-tag-prototype
+  phps-mode (tag &optional parent color)
+  "Return a prototype for TOKEN.
+Optional argument PARENT is a parent (containing) item.
+Optional argument COLOR indicates that color should be mixed in."
+  (let ((f (intern-soft (format "semantic-php-prototype-%s"
+                                (semantic-tag-class tag)))))
+    (funcall (if (fboundp f)
+                 f
+               'semantic-format-tag-prototype-default)
+             tag parent color)))
+
+(semantic-alias-obsolete 'semantic-php-prototype-nonterminal
+                         'semantic-format-tag-prototype-phps-mode "23.2")
+
+;; Include Tag Name
+;;
+
+;; Thanks Bruce Stephens
+(define-mode-local-override semantic-tag-include-filename phps-mode (tag)
+  "Return a suitable path for (some) PHP imports."
+  (let ((name (semantic-tag-name tag)))
+    (concat (mapconcat 'identity (split-string name "\\.") "/") ".php")))
+
+;; Documentation handler
+
+;; TODO Verify this
+(defsubst semantic-php-skip-spaces-backward ()
+  "Move point backward, skipping PHP whitespaces."
+  (skip-chars-backward " \n\r\t"))
+
+;; TODO Verify this
+(defsubst semantic-php-skip-spaces-forward ()
+  "Move point forward, skipping PHP whitespaces."
+  (skip-chars-forward " \n\r\t"))
+
+;; TODO Verify this
+(define-mode-local-override semantic-documentation-for-tag
+  phps-mode (&optional tag nosnarf)
+  "Find documentation from TAG and return it as a clean string.
+Php have documentation set in a comment preceding TAG's definition.
+Attempt to strip out comment syntactic sugar, unless optional argument
+NOSNARF is non-nil.
+If NOSNARF is 'lex, then return the semantic lex token."
+  (when (or tag (setq tag (semantic-current-tag)))
+    (with-current-buffer (semantic-tag-buffer tag)
+      (save-excursion
+        ;; Move the point at token start
+        (goto-char (semantic-tag-start tag))
+        (semantic-php-skip-spaces-forward)
+        ;; If the point already at "/**" (this occurs after a doc fix)
+        (if (looking-at "/\\*\\*")
+            nil
+          ;; Skip previous spaces
+          (semantic-php-skip-spaces-backward)
+          ;; Ensure point is after "*/" (phpdoc block comment end)
+          (condition-case nil
+              (backward-char 2)
+            (error nil))
+          (when (looking-at "\\*/")
+            ;; Move the point backward across the comment
+            (forward-char 2)              ; return just after "*/"
+            (forward-comment -1)          ; to skip the entire block
+            ))
+        ;; Verify the point is at "/**" (phpdoc block comment start)
+        (if (looking-at "/\\*\\*")
+            (let ((p (point))
+                  (c (semantic-doc-snarf-comment-for-tag 'lex)))
+              (when c
+                ;; Verify that the token just following the doc
+                ;; comment is the current one!
+                (goto-char (semantic-lex-token-end c))
+                (semantic-php-skip-spaces-forward)
+                (when (eq tag (semantic-current-tag))
+                  (goto-char p)
+                  (semantic-doc-snarf-comment-for-tag nosnarf)))))
+        ))))
+
+;;; Phpdoc facilities
+
+;; Phpdoc elements
+;;
+(defvar semantic-php-doc-line-tags nil
+  "Valid phpdoc line tags.
+Ordered following Sun's Tag Convention at
+<http://php.sun.com/products/jdk/phpdoc/writingdoccomments/index.html>")
+
+(defvar semantic-php-doc-with-name-tags nil
+  "Phpdoc tags which have a name.")
+
+(defvar semantic-php-doc-with-ref-tags nil
+  "Phpdoc tags which have a reference.")
+
+;; Optional phpdoc tags by classes of semantic tag
+;;
+(defvar semantic-php-doc-extra-type-tags nil
+  "Optional tags used in class/interface documentation.
+Ordered following Sun's Tag Convention.")
+
+(defvar semantic-php-doc-extra-function-tags nil
+  "Optional tags used in method/constructor documentation.
+Ordered following Sun's Tag Convention.")
+
+(defvar semantic-php-doc-extra-variable-tags nil
+  "Optional tags used in field documentation.
+Ordered following Sun's Tag Convention.")
+
+;; All phpdoc tags by classes of semantic tag
+;;
+(defvar semantic-php-doc-type-tags nil
+  "Tags allowed in class/interface documentation.
+Ordered following Sun's Tag Convention.")
+
+(defvar semantic-php-doc-function-tags nil
+  "Tags allowed in method/constructor documentation.
+Ordered following Sun's Tag Convention.")
+
+(defvar semantic-php-doc-variable-tags nil
+  "Tags allowed in field documentation.
+Ordered following Sun's Tag Convention.")
+
+;; Access to Phpdoc elements
+;;
+(defmacro semantic-php-doc-tag (name)
+  "Return doc tag from NAME.
+That is @NAME."
+  `(concat "@" ,name))
+
+(defsubst semantic-php-doc-tag-name (tag)
+  "Return name of the doc TAG symbol.
+That is TAG `symbol-name' without the leading `@'."
+  (substring (symbol-name tag) 1))
+
+(defun semantic-php-doc-keyword-before-p (k1 k2)
+  "Return non-nil if phpdoc keyword K1 is before K2."
+  (let* ((t1   (semantic-php-doc-tag k1))
+         (t2   (semantic-php-doc-tag k2))
+         (seq1 (and (semantic-lex-keyword-p t1)
+                    (plist-get (semantic-lex-keyword-get t1 'phpdoc)
+                               'seq)))
+         (seq2 (and (semantic-lex-keyword-p t2)
+                    (plist-get (semantic-lex-keyword-get t2 'phpdoc)
+                               'seq))))
+    (if (and (numberp seq1) (numberp seq2))
+        (<= seq1 seq2)
+      ;; Unknown tags (probably custom ones) are always after official
+      ;; ones and are not themselves ordered.
+      (or (numberp seq1)
+          (and (not seq1) (not seq2))))))
+
+(defun semantic-php-doc-keywords-map (fun &optional property)
+  "Run function FUN for each phpdoc keyword.
+Return the list of FUN results.  If optional PROPERTY is non nil only
+call FUN for phpdoc keywords which have a value for PROPERTY.  FUN
+receives two arguments: the phpdoc keyword and its associated
+'phpdoc property list.  It can return any value.  All nil values are
+removed from the result list."
+  (delq nil
+        (mapcar
+         #'(lambda (k)
+             (let* ((tag   (semantic-php-doc-tag k))
+                    (plist (semantic-lex-keyword-get tag 'phpdoc)))
+               (if (or (not property) (plist-get plist property))
+                   (funcall fun k plist))))
+         semantic-php-doc-line-tags)))
+
+;;; Mode setup
+;;
+
+(defun semantic-php-doc-setup ()
+  "Lazy initialization of phpdoc elements."
+  (or semantic-php-doc-line-tags
+      (setq semantic-php-doc-line-tags
+            (sort (mapcar #'semantic-php-doc-tag-name
+                          (semantic-lex-keywords 'phpdoc))
+                  #'semantic-php-doc-keyword-before-p)))
+
+  (or semantic-php-doc-with-name-tags
+      (setq semantic-php-doc-with-name-tags
+            (semantic-php-doc-keywords-map
+             #'(lambda (k p)
+                 k)
+             'with-name)))
+
+  (or semantic-php-doc-with-ref-tags
+      (setq semantic-php-doc-with-ref-tags
+            (semantic-php-doc-keywords-map
+             #'(lambda (k p)
+                 k)
+             'with-ref)))
+
+  (or semantic-php-doc-extra-type-tags
+      (setq semantic-php-doc-extra-type-tags
+            (semantic-php-doc-keywords-map
+             #'(lambda (k p)
+                 (if (memq 'type (plist-get p 'usage))
+                     k))
+             'opt)))
+
+  (or semantic-php-doc-extra-function-tags
+      (setq semantic-php-doc-extra-function-tags
+            (semantic-php-doc-keywords-map
+             #'(lambda (k p)
+                 (if (memq 'function (plist-get p 'usage))
+                     k))
+             'opt)))
+
+  (or semantic-php-doc-extra-variable-tags
+      (setq semantic-php-doc-extra-variable-tags
+            (semantic-php-doc-keywords-map
+             #'(lambda (k p)
+                 (if (memq 'variable (plist-get p 'usage))
+                     k))
+             'opt)))
+
+  (or semantic-php-doc-type-tags
+      (setq semantic-php-doc-type-tags
+            (semantic-php-doc-keywords-map
+             #'(lambda (k p)
+                 (if (memq 'type (plist-get p 'usage))
+                     k)))))
+
+  (or semantic-php-doc-function-tags
+      (setq semantic-php-doc-function-tags
+            (semantic-php-doc-keywords-map
+             #'(lambda (k p)
+                 (if (memq 'function (plist-get p 'usage))
+                     k)))))
+
+  (or semantic-php-doc-variable-tags
+      (setq semantic-php-doc-variable-tags
+            (semantic-php-doc-keywords-map
+             #'(lambda (k p)
+                 (if (memq 'variable (plist-get p 'usage))
+                     k)))))
+
+  )
+
+(provide 'phps-mode/semantic)
+
+;;; phps-semantic.el ends here
diff --git a/phps-syntax-table.el b/phps-syntax-table.el
new file mode 100644
index 0000000..0bd9e61
--- /dev/null
+++ b/phps-syntax-table.el
@@ -0,0 +1,73 @@
+;;; phps-mode/phps-syntax-table.el --- Major mode for PHP with Semantic 
integration
+
+;; Author: Christian Johansson <github.com/cjohansson>
+;; Maintainer: Christian Johansson <github.com/cjohansson>
+;; Created: 3 Mar 2018
+;; Modified: .
+;; Version: 0.1
+;; Keywords: tools, convenience
+;; URL: -
+
+;; Package-Requires: ((emacs "24"))
+
+;; Copyright (C) 2017 Christian Johansson
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; 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.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Spathoftware Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+
+;;; Commentary:
+
+
+;; Please see README.md from the same repository for extended documentation.
+
+
+;;; Code:
+
+
+(defvar phps-mode/syntax-table
+  (let ((phps-mode/syntax-table (make-syntax-table)))
+
+    ;; This is added so entity names with underscores can be more easily 
parsed as one word
+    (modify-syntax-entry ?_ "_" phps-mode/syntax-table)
+    ;; (modify-syntax-entry ?_ "w" phps-mode/syntax-table)
+
+    ;; Comment styles are same as C++
+    ;; (modify-syntax-entry ?/ ". 124b" phps-mode/syntax-table)
+    ;; (modify-syntax-entry ?* ". 23" phps-mode/syntax-table)
+    ;; (modify-syntax-entry ?\n "> b" phps-mode/syntax-table)
+
+    ;; From Old PHP-mode, analyse these
+    ;; (modify-syntax-entry ?_    "_" php-mode-syntax-table)
+    ;; (modify-syntax-entry ?`    "\"" php-mode-syntax-table)
+    ;; (modify-syntax-entry ?\"   "\"" php-mode-syntax-table)
+    ;; (modify-syntax-entry ?#    "< b" php-mode-syntax-table)
+    ;; (modify-syntax-entry ?\n   "> b" php-mode-syntax-table)
+    ;; (modify-syntax-entry ?$    "'" php-mode-syntax-table)
+    ;; (set (make-local-variable 'syntax-propertize-function) 
#'php-syntax-propertize-function)
+
+    phps-mode/syntax-table)
+  "Syntax table for phps-mode.")
+
+(defun phps-mode/syntax-table-init ()
+  "Apply syntax table."
+  ;; (setq font-lock-keywords-only t)
+  (set-syntax-table phps-mode/syntax-table))
+
+(provide 'phps-mode/syntax-table)
+
+;;; phps-syntax-table.el ends here
diff --git a/phps-tags.el b/phps-tags.el
new file mode 100644
index 0000000..73eee69
--- /dev/null
+++ b/phps-tags.el
@@ -0,0 +1,159 @@
+;;; phps-mode/phps-tags.el --- PHP LALR parser for Emacs
+
+;; Copyright (C) 2001-2006, 2009-2018 Free Software Foundation, Inc.
+
+;; Author: David Ponce <address@hidden>
+;; Maintainer: David Ponce <address@hidden>
+;; Created: 15 Dec 2001
+;; Keywords: syntax
+
+;; This file is not part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs 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.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; TODO Make similar to 
/Users/christianjohansson/Documents/emacs/nextstep/Emacs.app/Contents/Resources/lisp/cedet/semantic/wisent/java-tags.el.gz
+
+;;; Code:
+
+(require 'semantic/wisent)
+(require 'phps-mode/tags-wy "tags-wy")
+(require 'phps-mode/phps-semantic "phps-semantic")
+
+;;;;
+;;;; Simple parser error reporting function
+;;;;
+
+(defun wisent-php-parse-error (msg)
+  "Error reporting function called when a parse error occurs.
+MSG is the message string to report."
+;;   (let ((error-start (nth 2 wisent-input)))
+;;     (if (number-or-marker-p error-start)
+;;         (goto-char error-start)))
+  (message msg)
+  ;;(debug)
+  )
+
+;;;;
+;;;; Local context
+;;;;
+
+(define-mode-local-override semantic-get-local-variables
+  phps-mode ()
+  "Get local values from a specific context.
+Parse the current context for `field_declaration' nonterminals to
+collect tags, such as local variables or prototypes.
+This function override `get-local-variables'."
+  (let ((vars nil)
+        (ct (semantic-current-tag))
+        ;; We want nothing to do with funny syntaxing while doing this.
+        (semantic-unmatched-syntax-hook nil))
+    (while (not (semantic-up-context (point) 'function))
+      (save-excursion
+        (forward-char 1)
+        (setq vars
+              (append (semantic-parse-region
+                       (point)
+                       (save-excursion (semantic-end-of-context) (point))
+                       'field_declaration
+                       0 t)
+                      vars))))
+    ;; Add 'this' if in a fcn
+    (when (semantic-tag-of-class-p ct 'function)
+      ;; Append a new tag THIS into our space.
+      (setq vars (cons (semantic-tag-new-variable
+                        "this" (semantic-tag-name 
(semantic-current-tag-parent))
+                        nil)
+                       vars)))
+    vars))
+
+;;; Analyzer and type cache support
+(define-mode-local-override semantic-analyze-split-name phps-mode (name)
+  "Split up tag names on colon . boundaries."
+  (let ((ans (split-string name "\\->")))
+    (if (= (length ans) 1)
+        name
+      (delete "" ans))))
+
+(define-mode-local-override semantic-analyze-unsplit-name phps-mode (namelist)
+  "Assemble the list of names NAMELIST into a namespace name."
+  (mapconcat 'identity namelist "->"))
+
+
+
+;;;; Semantic integration of the PHP LALR parser
+
+;; In semantic/imenu.el, not part of Emacs.
+(defvar semantic-imenu-summary-function)
+
+;;;###autoload
+(defun phps-mode/tags-init ()
+  "Hook run to setup Semantic in `phps-mode'.
+Use the alternate LALR(1) parser."
+
+  (phps-mode-tags--install-parser)
+
+  (require 'semantic/bovine/debug)
+
+  (setq
+
+   ;; Semantic requires this expression for line-comments,
+   ;; if lexing without major mode
+   semantic-lex-comment-regex "\\s<\\|\\(/\\*\\|//\\)"
+
+   ;; Lexical analysis
+   semantic-lex-number-expression semantic-php-number-regexp
+   semantic-lex-analyzer 'phps-mode-tags-lexer
+
+   ;; Parsing
+   semantic-tag-expand-function 'semantic-php-expand-tag
+
+   ;; Environment
+   semantic-imenu-summary-function 'semantic-format-tag-prototype
+   imenu-create-index-function 'semantic-create-imenu-index
+   semantic-type-relation-separator-character '("::" "->")
+   semantic-command-separation-character ";"
+   semantic-debug-parser-class 'semantic-bovine-debug-parser
+
+   ;; speedbar and imenu buckets name
+   semantic-symbol->name-assoc-list-for-type-parts
+
+   ;; in type parts
+   ;; TODO Add constants to this?
+   '((package . "Namespaces")
+     (type     . "Classes")
+     (variable . "Variables")
+     (function . "Functions"))
+   semantic-symbol->name-assoc-list
+
+   ;; everywhere
+   (append semantic-symbol->name-assoc-list-for-type-parts
+           '((namespace  . "Namespaces")))
+
+   ;; navigation inside 'type children
+   senator-step-at-tag-classes '(function variable)
+
+   ;; Remove 'recursive from the default semanticdb find throttle
+   ;; since php imports never recurse.
+   semanticdb-find-default-throttle
+
+   (remq 'recursive (default-value 'semanticdb-find-default-throttle)))
+
+  ;; Setup phpdoc stuff
+  (semantic-php-doc-setup))
+
+(provide 'phps-mode/phps-tags)
+
+;;; phps-tags.el ends here
diff --git a/phps-test-lexer.el b/phps-test-lexer.el
new file mode 100644
index 0000000..f5f5f4f
--- /dev/null
+++ b/phps-test-lexer.el
@@ -0,0 +1,243 @@
+;;; phps-test-lexer.el --- Tests for Semantic Lexer
+
+;; Author: Christian Johansson <github.com/cjohansson>
+;; Maintainer: Christian Johansson <github.com/cjohansson>
+;; Created: 3 Mar 2018
+;; Modified: .
+;; Version: 0.1
+;; Keywords: tools, convenience
+;; URL: -
+
+;; Copyright (C) 2018 Christian Johansson
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; 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.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Spathoftware Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+
+;;; Commentary:
+
+
+;; Run from terminal make lexer-test
+
+
+;;; Code:
+
+
+(autoload 'phps-mode "phps-mode")
+(autoload 'phps-mode/lexer "phps-lexer")
+
+(require 'ert)
+
+(defmacro phps-mode/with-test-buffer (source &rest body)
+  "Set up test buffer with SOURCE and BODY."
+  `(let ((test-buffer (generate-new-buffer "test")))
+     (switch-to-buffer test-buffer)
+     (insert ,source)
+     (goto-char 0)
+     ;;,(message "\nTesting buffer:\n'%s'\n" source)
+     (phps-mode)
+     (phps-mode/lexer-init)
+     ,@body
+     (kill-buffer test-buffer)
+     ))
+
+(defun phps-mode/token-stream-to-string (token-stream)
+  "Return a string from a TOKEN-STREAM."
+  (let ((return ""))
+    (dolist (item token-stream)
+      (setq return (concat return (format " %s" (car item)))))
+    return))
+
+(defun phps-mode/test-lexer--script-boundaries ()
+  "Run test for lexer."
+
+  (phps-mode/with-test-buffer
+   "<?php\texit;\t?>"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG T_EXIT ; ; T_CLOSE_TAG"))))
+
+  (phps-mode/with-test-buffer
+   "<?php\nexit;\n?>"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG T_EXIT ; ; T_CLOSE_TAG"))))
+
+  (phps-mode/with-test-buffer
+   "<?php exit; ?>"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG T_EXIT ; ; T_CLOSE_TAG"))))
+
+  (phps-mode/with-test-buffer
+   "<html><head>blabla</head<body>\n\n \t<?php\nexit;\n?>\n\n</body></html>"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG T_EXIT ; ; T_CLOSE_TAG"))))
+
+  (phps-mode/with-test-buffer
+   "\n\n \t<html><title>echo 
\"Blaha\";</title><?php\n\n\nexit?>\n\n<html><random /></html><?php exit ?>"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG T_EXIT ; T_CLOSE_TAG T_OPEN_TAG 
T_EXIT ; T_CLOSE_TAG"))))
+
+  )
+
+(defun phps-mode/test-lexer--simple-tokens ()
+  "Run test for simple tokens."
+
+  (phps-mode/with-test-buffer
+   "<?php $var EXIT die function return yield from yield try catch finally 
throw if elseif endif else while endwhile do for endfor foreach endforeach 
declare enddeclare instanceof as switch endswitch case default break continue 
goto echo print class interface trait extends implements :: \\ ... ?? new clone 
var (int) (integer) (real) (double) (float) (string) (binary) (array) (object) 
(boolean) (bool) (unset) eval include include_once require require_once 
namespace use insteadof global is [...]
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     ;; (message "Tokens %s" string-tokens)
+     (should (equal string-tokens " T_OPEN_TAG T_VARIABLE T_EXIT T_DIE 
T_FUNCTION T_RETURN T_YIELD_FROM T_YIELD T_TRY T_CATCH T_FINALLY T_THROW T_IF 
T_ELSEIF T_ENDIF T_ELSE T_WHILE T_ENDWHILE T_DO T_FOR T_ENDFOR T_FOREACH 
T_ENDFOREACH T_DECLARE T_ENDDECLARE T_INSTANCEOF T_AS T_SWITCH T_ENDSWITCH 
T_CASE T_DEFAULT T_BREAK T_CONTINUE T_GOTO T_ECHO T_PRINT T_CLASS T_INTERFACE 
T_TRAIT T_EXTENDS T_IMPLEMENTS T_PAAMAYIM_NEKUDOTAYIM T_NS_SEPARATOR T_ELLIPSIS 
T_COALESCE T_NEW T_CLONE T_VAR T_INT_ [...]
+
+  )
+
+(defun phps-mode/test-lexer--complex-tokens ()
+  "Run test for complex tokens."
+
+  (phps-mode/with-test-buffer
+   "<?php $var->property;"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG T_VARIABLE T_OBJECT_OPERATOR 
T_STRING ;"))))
+
+  ;; Double quoted strings with variables
+  (phps-mode/with-test-buffer
+   "<?php echo \"My $variable is here\"; echo \"you know\";"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG T_ECHO \" 
T_ENCAPSED_AND_WHITESPACE T_VARIABLE T_CONSTANT_ENCAPSED_STRING \" ; T_ECHO 
T_CONSTANT_ENCAPSED_STRING ;"))))
+  (phps-mode/with-test-buffer
+   "<?php echo \"My ${variable} is here 1\";"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG T_ECHO \" 
T_ENCAPSED_AND_WHITESPACE T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME } 
T_CONSTANT_ENCAPSED_STRING \" ;"))))
+  (phps-mode/with-test-buffer
+   "<?php echo \"Mine {$first_variable} is here and my $second is there.\";"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG T_ECHO \" 
T_ENCAPSED_AND_WHITESPACE T_CURLY_OPEN T_VARIABLE } T_CONSTANT_ENCAPSED_STRING 
T_VARIABLE T_CONSTANT_ENCAPSED_STRING \" ;"))))
+  (phps-mode/with-test-buffer
+   "<?php echo \" Hello $variable[0], how are you?\";"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG T_ECHO \" 
T_ENCAPSED_AND_WHITESPACE T_VARIABLE T_NUM_STRING ] T_CONSTANT_ENCAPSED_STRING 
\" ;"))))
+
+  ;; Heredoc
+  (phps-mode/with-test-buffer
+   "<?php echo <<<\"MYLABEL\"\nline 1\n line 2\nMYLABEL\n;"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG T_ECHO T_START_HEREDOC 
T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC ;"))))
+  (phps-mode/with-test-buffer
+   "<?php echo <<<MYLABEL\nline 1\n line 2\nMYLABEL\n;"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG T_ECHO T_START_HEREDOC 
T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC ;"))))
+  (phps-mode/with-test-buffer
+   "<?php echo <<<\"MYLABEL\"\nMYLABEL\n"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG T_ECHO T_START_HEREDOC 
T_END_HEREDOC"))))
+
+  ;; Test heredoc with variables $, {$, ${ here
+  (phps-mode/with-test-buffer
+   "<?php echo <<<\"MYLABEL\"\nline 1 $variable1\n line 2\n${variable2} line 
3\n line {$variable3} here\nline 5 $variable[3] here\nMYLABEL;\n"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG T_ECHO T_START_HEREDOC 
T_ENCAPSED_AND_WHITESPACE T_VARIABLE T_ENCAPSED_AND_WHITESPACE 
T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME } T_ENCAPSED_AND_WHITESPACE 
T_CURLY_OPEN T_VARIABLE } T_ENCAPSED_AND_WHITESPACE T_VARIABLE T_NUM_STRING ] 
T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC ;"))))
+
+  ;; Nowdoc
+  (phps-mode/with-test-buffer
+   "<?php echo <<<'MYLABEL'\nline 1\n line 2\nMYLABEL;\n"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG T_ECHO T_START_HEREDOC 
T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC ;"))))
+
+  ;; Backquotes
+  (phps-mode/with-test-buffer
+   "<?php `echo \"HELLO\"`;"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG ` T_CONSTANT_ENCAPSED_STRING ` 
;"))))
+  (phps-mode/with-test-buffer
+   "<?php `echo \"HELLO $variable or {$variable2} or ${variable3} or 
$variable[index][0] here\"`;"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG ` T_CONSTANT_ENCAPSED_STRING 
T_VARIABLE T_CONSTANT_ENCAPSED_STRING T_CURLY_OPEN T_VARIABLE } 
T_CONSTANT_ENCAPSED_STRING T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME } 
T_CONSTANT_ENCAPSED_STRING T_VARIABLE T_STRING ] T_CONSTANT_ENCAPSED_STRING ` 
;"))))
+
+  )
+
+(defun phps-mode/test-lexer--namespaces ()
+  "Run test for namespaces."
+
+  (phps-mode/with-test-buffer
+   "<?php\nnamespace MyNameSpace{\n\tclass MyClass {\n\t\tpublic function 
__construct() {\n\t\t\texit;\n\t\t}\n\t}\n}\n"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG T_NAMESPACE T_STRING { T_CLASS 
T_STRING { T_PUBLIC T_FUNCTION T_STRING ( ) { T_EXIT ; } } }"))))
+
+  (phps-mode/with-test-buffer
+   "<?php\nNAMESPACE MyNameSpace;\nCLASS MyClass {\n\tpublic function 
__construct() {\n\t\texit;\n\t}\n}\n"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG T_NAMESPACE T_STRING { T_CLASS 
T_STRING { T_PUBLIC T_FUNCTION T_STRING ( ) { T_EXIT ; } } }"))))
+  )
+
+(defun phps-mode/test-lexer--errors ()
+  "Run test for errors."
+
+  (phps-mode/with-test-buffer
+   "<?php\necho \"My neverending double quotation\n"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG T_ECHO T_ERROR"))))
+
+  (phps-mode/with-test-buffer
+   "<?php\n`My neverending backquotes\n"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG ` T_ERROR"))))
+
+  (phps-mode/with-test-buffer
+   "<?php\n<<<LABEL\nMy neverending heredoc\ngoes on forever\n"
+   (let* ((tokens (semantic-lex-buffer))
+          (string-tokens (phps-mode/token-stream-to-string tokens)))
+     (should (equal string-tokens " T_OPEN_TAG T_START_HEREDOC T_ERROR"))))
+
+)
+
+(defun phps-mode/test-lexer ()
+  "Run test for lexer."
+  ;; (message "-- Running all tests for lexer... --\n")
+  ;; (setq debug-on-error t)
+  (phps-mode/test-lexer--script-boundaries)
+  (phps-mode/test-lexer--simple-tokens)
+  (phps-mode/test-lexer--complex-tokens)
+  (phps-mode/test-lexer--namespaces)
+  (phps-mode/test-lexer--errors)
+  ;; (message "\n-- Ran all tests for lexer. --")
+  )
+
+(phps-mode/test-lexer)
+
+(provide 'phps-mode/test-lexer)
+
+;;; phps-test-lexer.el ends here
diff --git a/phps-test-parser.el b/phps-test-parser.el
new file mode 100644
index 0000000..ad873ba
--- /dev/null
+++ b/phps-test-parser.el
@@ -0,0 +1,52 @@
+;;; phps-test-parser.el --- Tests for Semantic parser
+
+;; Author: Christian Johansson <github.com/cjohansson>
+;; Maintainer: Christian Johansson <github.com/cjohansson>
+;; Created: 3 Mar 2018
+;; Modified: .
+;; Version: 0.1
+;; Keywords: tools, convenience
+;; URL: -
+
+;; Copyright (C) 2018 Christian Johansson
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; 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.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Spathoftware Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+
+;;; Commentary:
+
+
+;; Run from terminal make test-parser
+
+
+;;; Code:
+
+
+(defun phps-test-parser()
+  "Run test for lexer."
+  (message "-- Running all tests for parser... --\n")
+  ;; (setq debug-on-error t)
+
+  (message "\n-- Ran all tests for parser. --")
+  )
+
+(phps-test-parser)
+
+(provide 'phps-test-parser)
+
+;;; phps-test-parser.el ends here
diff --git a/tests/php/class.php b/tests/php/class.php
new file mode 100644
index 0000000..e43c12b
--- /dev/null
+++ b/tests/php/class.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Some comments here
+ *  @todo was here
+ */
+
+class MyClass {
+
+    public function myMethod()
+    {
+        echo "Some stuff here"; // Just a comment
+    }
+
+    public function myMethod2() {
+           echo "Some stuff here 2";
+    }
+
+}
diff --git a/tests/php/functions.php b/tests/php/functions.php
new file mode 100644
index 0000000..139ca4d
--- /dev/null
+++ b/tests/php/functions.php
@@ -0,0 +1,6 @@
+<?php
+
+function myFunctionA($myArg1, $myArg2)
+{
+    echo "some stuff";
+}
diff --git a/tests/php/interfaces.php b/tests/php/interfaces.php
new file mode 100644
index 0000000..de32903
--- /dev/null
+++ b/tests/php/interfaces.php
@@ -0,0 +1,9 @@
+<?php
+
+interface myInterface2 {
+    function myFunction2();
+}
+
+interface myInterface extends myInterface2  {
+    function myFunction();
+}
diff --git a/tests/php/namespace.php b/tests/php/namespace.php
new file mode 100644
index 0000000..2782c8e
--- /dev/null
+++ b/tests/php/namespace.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace MyNameSpace;
+
+function myNamespacedFunction() {
+    echo 'here';
+}
+
+class MyClass {
+    public function myFunction()
+    {
+        echo "Do something here";
+    }
+}
+
+class MyClass2 {
+
+}
diff --git a/tests/php/namespaces.php b/tests/php/namespaces.php
new file mode 100644
index 0000000..7b03f82
--- /dev/null
+++ b/tests/php/namespaces.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace MyNameSpaceA {
+    class MyClassA {
+        public function myMethodA()
+        {
+                echo "Do something here";
+        }
+    }
+}
+
+namespace MyNameSpaceB {
+    class MyClassB {
+        public function myMethodB()
+        {
+            echo "Do something here";
+        }
+    }
+}



reply via email to

[Prev in Thread] Current Thread [Next in Thread]