Skip to content
Snippets Groups Projects
Commit e1a13fae authored by Robert Plummer's avatar Robert Plummer Committed by Marijn Haverbeke
Browse files

[ebnf mode] Add

parent cb397ba0
No related branches found
No related tags found
No related merge requests found
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../javascript/javascript"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../javascript/javascript"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineMode("ebnf", function (config) {
var commentType = {
slash: 0,
parenthesis: 1
},
stateType = {
comment: 0,
_string: 1,
characterClass: 2
},
peek,
bracesMode = null;
if (config.bracesMode) {
bracesMode = CodeMirror.getMode(config, config.bracesMode);
}
return {
startState: function () {
return {
stringType: null,
commentType: null,
braced: 0,
lhs: true,
localState: null,
stack: [],
inDefinition: false
};
},
token: function (stream, state) {
if (!stream) return;
//check for state changes
if (state.stack.length === 0) {
//strings
if ((stream.peek() == '"') || (stream.peek() == "'")) {
state.stringType = stream.peek();
stream.next(); // Skip quote
state.stack.unshift(stateType._string);
}
//comments starting with /*
else if (stream.match(/^\/\*/)) {
state.stack.unshift(stateType.comment);
state.commentType = commentType.slash;
}
//comments starting with (*
else if (stream.match(/^\(\*/)) {
state.stack.unshift(stateType.comment);
state.commentType = commentType.parenthesis;
}
}
//return state
//stack has
switch (state.stack[0]) {
case stateType._string:
while (state.stack[0] === stateType._string && !stream.eol()) {
if (stream.peek() === state.stringType) {
stream.next(); // Skip quote
state.stack.shift(); // Clear flag
} else if (stream.peek() === '\\') {
stream.next();
stream.next();
} else {
stream.match(/^.[^\\\"\']*/);
}
}
return state.lhs ? "property string" : "string"; // Token style
case stateType.comment:
while (state.stack[0] === stateType.comment && !stream.eol()) {
if (state.commentType === commentType.slash && stream.match(/\*\//)) {
state.stack.shift(); // Clear flag
state.commentType = null;
} else if (state.commentType === commentType.parenthesis && stream.match(/\*\)/)) {
state.stack.shift(); // Clear flag
state.commentType = null;
} else {
stream.match(/^.[^\*]*/);
}
}
return "comment";
case stateType.characterClass:
while (state.stack[0] === stateType.characterClass && !stream.eol()) {
if (!(stream.match(/^[^\]\\]+/) || stream.match(/^\\./))) {
state.stack.shift();
}
}
return 'operator';
}
peek = stream.peek();
if (bracesMode !== null && (state.braced || peek === '{')) {
if (state.localState === null) {
state.localState = bracesMode.startState();
}
var token = bracesMode.token(stream, state.localState),
text = stream.current();
if (!token) {
for (var i = 0; i < text.length; i++) {
if (text[i] === '{') {
if (state.braced === 0) {
token = 'matchingbracket';
}
state.braced++;
} else if (text[i] === '}') {
state.braced--;
if (state.braced === 0) {
token = 'matchingbracket';
}
}
}
}
return token;
}
//no stack
switch (peek) {
case '[':
stream.next();
state.stack.unshift(stateType.characterClass);
return 'bracket';
case ':':
case '|':
case ';':
stream.next();
return 'operator';
case '%':
if (stream.match('%%')) {
return 'header';
}
else if (stream.match(/[%][A-Za-z]+/)) {
return 'keyword';
} else if (stream.match(/[%][}]/)) {
return 'matchingbracket';
}
break;
case '/':
if (stream.match(/[/][A-Za-z]+/)) {
return 'keyword';
}
case '\\':
if (stream.match(/[\][a-z]+/)) {
return 'string-2';
}
case '.':
if (stream.match('.')) {
return 'atom';
}
case '*':
case '-':
case '+':
case '^':
if (stream.match(peek)) {
return 'atom';
}
case '$':
if (stream.match('$$')) {
return 'builtin';
} else if (stream.match(/[$][0-9]+/)) {
return 'variable-3'
}
case '<':
if (stream.match(/<<[a-zA-Z_]+>>/)) {
return 'builtin';
}
}
if (stream.match(/^\/\//)) {
stream.skipToEnd();
return "comment";
}
else if (stream.match(/return/)) {
return 'operator';
}
else if (stream.match(/^[a-zA-Z_][a-zA-Z0-9_]*/)) {
if (stream.match(/(?=[\(.])/)) {
return 'variable';
} else if (stream.match(/(?=[\s\n]*[:=])/)) {
return 'def';
}
return 'variable-2';
}
else if (['[', ']', '(', ')'].indexOf(stream.peek()) != -1) {
stream.next();
return 'bracket';
}
else if (!stream.eatSpace()) {
stream.next();
}
return null;
}
};
});
});
<!doctype html>
<html>
<head>
<title>CodeMirror: EBNF Mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="../javascript/javascript.js"></script>
<script src="ebnf.js"></script>
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
</head>
<body>
<div id=nav>
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/codemirror/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">EBNF Mode</a>
</ul>
</div>
<article>
<h2>EBNF Mode (bracesMode setting = "javascript")</h2>
<form><textarea id="code" name="code">
/* description: Parses end executes mathematical expressions. */
/* lexical grammar */
%lex
%%
\s+ /* skip whitespace */
[0-9]+("."[0-9]+)?\b return 'NUMBER';
"*" return '*';
"/" return '/';
"-" return '-';
"+" return '+';
"^" return '^';
"(" return '(';
")" return ')';
"PI" return 'PI';
"E" return 'E';
&lt;&lt;EOF&gt;&gt; return 'EOF';
/lex
/* operator associations and precedence */
%left '+' '-'
%left '*' '/'
%left '^'
%left UMINUS
%start expressions
%% /* language grammar */
expressions
: e EOF
{print($1); return $1;}
;
e
: e '+' e
{$$ = $1+$3;}
| e '-' e
{$$ = $1-$3;}
| e '*' e
{$$ = $1*$3;}
| e '/' e
{$$ = $1/$3;}
| e '^' e
{$$ = Math.pow($1, $3);}
| '-' e %prec UMINUS
{$$ = -$2;}
| '(' e ')'
{$$ = $2;}
| NUMBER
{$$ = Number(yytext);}
| E
{$$ = Math.E;}
| PI
{$$ = Math.PI;}
;</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: {name: "ebnf"},
lineNumbers: true,
bracesMode: 'javascript'
});
</script>
<h3>The EBNF Mode</h3>
<p> Created by <a href="https://github.com/robertleeplummerjr">Robert Plummer</a></p>
</article>
</body>
</html>
......@@ -47,6 +47,7 @@ option.</p>
<li><a href="diff/index.html">diff</a></li>
<li><a href="dtd/index.html">DTD</a></li>
<li><a href="dylan/index.html">Dylan</a></li>
<li><a href="ebnf/index.html">EBNF</a></li>
<li><a href="ecl/index.html">ECL</a></li>
<li><a href="eiffel/index.html">Eiffel</a></li>
<li><a href="erlang/index.html">Erlang</a></li>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment