Removed server mode from peglint and updated documentation

This commit is contained in:
yhirose 2019-02-09 08:55:28 -05:00
parent cc053fd9ad
commit 06fc879371
6 changed files with 7 additions and 2910 deletions

View File

@ -4,9 +4,9 @@ cpp-peglib
[![Build Status](https://travis-ci.org/yhirose/cpp-peglib.svg?branch=master)](https://travis-ci.org/yhirose/cpp-peglib) [![Build Status](https://travis-ci.org/yhirose/cpp-peglib.svg?branch=master)](https://travis-ci.org/yhirose/cpp-peglib)
[![Bulid Status](https://ci.appveyor.com/api/projects/status/github/yhirose/cpp-peglib?branch=master&svg=true)](https://ci.appveyor.com/project/yhirose/cpp-peglib) [![Bulid Status](https://ci.appveyor.com/api/projects/status/github/yhirose/cpp-peglib?branch=master&svg=true)](https://ci.appveyor.com/project/yhirose/cpp-peglib)
C++11 header-only [PEG](http://en.wikipedia.org/wiki/Parsing_expression_grammar) (Parsing Expression Grammars) library. C++11 header-only [PEG](http://en.wikipedia.org/wiki/Parsing_expression_grammar) (Parsing Expression Grammars) library. You can start using it right away just by including `peglib.h` in your project.
*cpp-peglib* tries to provide more expressive parsing experience in a simple way. This library depends on only one header file. So, you can start using it right away just by including `peglib.h` in your project. You can also try the online version at https://yhirose.github.io/cpp-peglib.
The PEG syntax is well described on page 2 in the [document](http://www.brynosaurus.com/pub/lang/peg.pdf). *cpp-peglib* also supports the following additional syntax for now: The PEG syntax is well described on page 2 in the [document](http://www.brynosaurus.com/pub/lang/peg.pdf). *cpp-peglib* also supports the following additional syntax for now:
@ -433,7 +433,7 @@ peglint - PEG syntax lint utility
> cmake .. > cmake ..
> make > make
> ./peglint > ./peglint
usage: peglint [--ast] [--optimize_ast_nodes|--opt] [--source text] [--server [PORT]] [--trace] [grammar file path] [source file path] usage: peglint [--ast] [--optimize_ast_nodes|--opt] [--source text] [--trace] [grammar file path] [source file path]
``` ```
### Lint grammar ### Lint grammar

View File

@ -1,13 +1,4 @@
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 2.8)
include_directories(..) include_directories(..)
add_definitions("-std=c++11") add_definitions("-std=c++11")
add_executable(peglint peglint.cc server.cc) add_executable(peglint peglint.cc)
if(WIN32)
target_link_libraries(peglint wsock32 ws2_32)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
#set(add_link_deps pthread)
target_link_libraries(peglint pthread)
endif()

View File

@ -4,5 +4,5 @@ peglint
The lint utility for PEG. The lint utility for PEG.
``` ```
usage: peglint [--ast] [--optimize_ast_nodes|--opt] [--server [PORT]] [--trace] [grammar file path] [source file path] usage: peglint [--ast] [--optimize_ast_nodes|--opt] [--trace] [grammar file path] [source file path]
``` ```

File diff suppressed because it is too large Load Diff

View File

@ -10,8 +10,6 @@
using namespace std; using namespace std;
int run_server(int port, const vector<char>& syntax, const vector<char>& source);
bool read_file(const char* path, vector<char>& buff) bool read_file(const char* path, vector<char>& buff)
{ {
ifstream ifs(path, ios::in | ios::binary); ifstream ifs(path, ios::in | ios::binary);
@ -33,8 +31,6 @@ int main(int argc, const char** argv)
auto opt_help = false; auto opt_help = false;
auto opt_source = false; auto opt_source = false;
vector<char> source; vector<char> source;
auto opt_server = false;
int port = 1234;
auto opt_trace = false; auto opt_trace = false;
vector<const char*> path_list; vector<const char*> path_list;
@ -53,11 +49,6 @@ int main(int argc, const char** argv)
std::string text = argv[argi++]; std::string text = argv[argi++];
source.assign(text.begin(), text.end()); source.assign(text.begin(), text.end());
} }
} else if (string("--server") == arg) {
opt_server = true;
if (argi < argc) {
port = std::stoi(argv[argi++]);
}
} else if (string("--trace") == arg) { } else if (string("--trace") == arg) {
opt_trace = true; opt_trace = true;
} else { } else {
@ -65,28 +56,11 @@ int main(int argc, const char** argv)
} }
} }
if ((path_list.empty() && !opt_server) || opt_help) { if (path_list.empty() || opt_help) {
cerr << "usage: peglint [--ast] [--optimize_ast_nodes|--opt] [--source text] [--server [PORT]] [--trace] [grammar file path] [source file path]" << endl; cerr << "usage: peglint [--ast] [--optimize_ast_nodes|--opt] [--source text] [--trace] [grammar file path] [source file path]" << endl;
return 1; return 1;
} }
// Sever mode
if (opt_server) {
vector<char> syntax;
if (path_list.size() >= 1 && !read_file(path_list[0], syntax)) {
cerr << "can't open the grammar file." << endl;
return -1;
}
if (path_list.size() >= 2 && !read_file(path_list[1], source)) {
cerr << "can't open the code file." << endl;
return -1;
}
return run_server(port, syntax, source);
}
// Check PEG grammar // Check PEG grammar
auto syntax_path = path_list[0]; auto syntax_path = path_list[0];

View File

@ -1,371 +0,0 @@
#include "httplib.h"
#include "peglib.h"
#include <cstdio>
#include <functional>
#include <iomanip>
#include <sstream>
using namespace httplib;
using namespace std;
static string indexHTML = R"(
<!DOCTYPE html>
<html lang="en">
<head>
<title>PEG Playground</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
text-decoration: none;
list-style: none;
}
body {
display: flex;
display: -webkit-flex;
flex-direction: column;
-webkit-flex-direction: column;
height: 100vh;
}
#main {
flex: 1;
-webkit-flex: 1;
display: none;
}
.editor-container {
flex: 1;
-webkit-flex: 1;
width: 100%;
display: flex;
display: -webkit-flex;
flex-direction: column;
-webkit-flex-direction: column;
margin: 8px;
}
.editor-container:first-child {
margin-right: 0;
}
.editor-header {
display: flex;
display: -webkit-flex;
height: 48px;
padding: 4px 8px;
}
.editor-header > li:last-child {
margin-left: auto;
}
.editor-header > li > span {
height: 38px;
line-height: 38px;
}
.editor-header > li > a {
height: 38px;
line-height: 38px;
padding: .3em .5em;
border: 1px solid red;
}
.editor-validation {
padding: 9px 11px;
color: green;
background-color: lightgreen;
border-radius: 5px;
}
.editor-validation-invalid {
color: red;
background-color: pink;
}
.editor-area {
flex: 1;
-webkit-flex: 1;
border: 1px solid lightgray;
}
.editor-info {
margin-top: 6px;
height: 160px;
border: 1px solid lightgray;
padding: 8px;
}
.editor-info li {
cursor: pointer;
}
</style>
</head>
<body>
<div id="main">
<div class="editor-container">
<ul class="editor-header">
<li><span>Grammar:</span></li>
<li><span id="grammar-validation" class="editor-validation">Valid</span></li>
</ul>
<pre id="grammar-editor" class="editor-area">{{syntax}}</pre>
<div id="grammar-info" class="editor-info"></div>
</div>
<div class="editor-container">
<ul class="editor-header">
<li><span>Code:</span></li>
<li><span id="code-validation" class="editor-validation">Valid</span></li>
</ul>
<pre id="code-editor" class="editor-area">{{source}}</pre>
<pre id="code-ast" class="editor-area"></pre>
<pre id="code-ast-optimized" class="editor-area"></pre>
<div id="code-info" class="editor-info"></div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.9/ace.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
// Setup editros
var grammar = ace.edit("grammar-editor");
grammar.setShowPrintMargin(false);
grammar.setValue(localStorage.getItem('grammarText'));
grammar.moveCursorTo(0, 0);
var code = ace.edit("code-editor");
code.setShowPrintMargin(false);
code.setValue(localStorage.getItem('codeText'));
code.moveCursorTo(0, 0);
var codeAst = ace.edit("code-ast");
codeAst.setShowPrintMargin(false);
codeAst.setOptions({
readOnly: true,
highlightActiveLine: false,
highlightGutterLine: false
})
codeAst.renderer.$cursorLayer.element.style.opacity=0;
var codeAstOptimized = ace.edit("code-ast-optimized");
codeAstOptimized.setShowPrintMargin(false);
codeAstOptimized.setOptions({
readOnly: true,
highlightActiveLine: false,
highlightGutterLine: false
})
codeAstOptimized.renderer.$cursorLayer.element.style.opacity=0;
var generateErrorListHTML = function (errors) {
var html = '<ul>';
html += $.map(errors, function (x) {
return '<li data-ln="' + x.ln + '" data-col="' + x.col + '"><span>' + x.ln + ':' + x.col + '</span> <span>' + x.msg + '</span></li>';
}).join('');
html += '<ul>';
return html;
};
var parse = function () {
var $grammarValidation = $('#grammar-validation');
var $grammarInfo = $('#grammar-info');
var grammarText = grammar.getValue();
var $codeValidation = $('#code-validation');
var $codeInfo = $('#code-info');
var codeText = code.getValue();
localStorage.setItem('grammarText', grammarText);
localStorage.setItem('codeText', codeText);
$grammarInfo.html('');
$grammarValidation.hide();
$codeInfo.html('');
$codeValidation.hide();
codeAst.setValue('');
codeAstOptimized.setValue('');
if (grammarText.length === 0) {
return;
}
$.post("/parse", {
grammar: grammarText,
code: codeText
}).done(function (data) {
var isValid = data.grammar.length === 0;
if (isValid) {
$grammarValidation.removeClass('editor-validation-invalid').text('Valid').show();
var isValid = data.code.length === 0;
if (isValid) {
codeAst.insert(data.ast);
codeAstOptimized.insert(data.astOptimized);
$codeValidation.removeClass('editor-validation-invalid').text('Valid').show();
} else {
var html = generateErrorListHTML(data.code);
$codeInfo.html(html);
$codeValidation.addClass('editor-validation-invalid').text('Invalid').show();
}
} else {
var html = generateErrorListHTML(data.grammar);
$grammarInfo.html(html);
$grammarValidation.addClass('editor-validation-invalid').text('Invalid').show();
}
});
};
// Event handing for text editiing
var timer;
var setupTimer = function () {
clearTimeout(timer);
timer = setTimeout(parse, 750);
};
grammar.getSession().on('change', setupTimer);
code.getSession().on('change', setupTimer);
// Event handing in the info area
var makeOnClickInInfo = function (editor) {
return function () {
var el = $(this);
editor.navigateTo(el.data('ln') - 1, el.data('col') - 1);
editor.focus();
}
};
$('#grammar-info').on('click', 'li', makeOnClickInInfo(grammar));
$('#code-info').on('click', 'li', makeOnClickInInfo(code));
// Show page
$('#main').css({
'display': 'flex',
'display': '-webkit-flex'
});
// Initial parse
parse();
</script>
</body>
</html>
)";
// https://stackoverflow.com/questions/7724448/simple-json-string-escape-for-c/33799784#33799784
std::string escape_json(const std::string &s) {
std::ostringstream o;
for (auto c : s) {
if (c == '"' || c == '\\' || ('\x00' <= c && c <= '\x1f')) {
o << "\\u"
<< std::hex << std::setw(4) << std::setfill('0') << (int)c;
} else {
o << c;
}
}
return o.str();
}
function<void (size_t, size_t, const string&)> makeJSONFormatter(string& json)
{
auto init = make_shared<bool>(true);
return [&json, init](size_t ln, size_t col, const string& msg) mutable {
if (!init) {
json += ",";
}
json += "{";
json += R"("ln":)" + to_string(ln) + ",";
json += R"("col":)" + to_string(col) + ",";
json += R"("msg":")" + escape_json(msg) + R"(")";
json += "}";
*init = false;
};
}
bool parse_grammar(const string& text, peg::parser& peg, string& json)
{
peg.log = makeJSONFormatter(json);
json += "[";
auto ret = peg.load_grammar(text.data(), text.size());
json += "]";
return ret;
}
bool parse_code(const string& text, peg::parser& peg, string& json, shared_ptr<peg::Ast>& ast)
{
peg.enable_ast();
peg.log = makeJSONFormatter(json);
json += "[";
auto ret = peg.parse_n(text.data(), text.size(), ast);
json += "]";
return ret;
}
string replace_all(const string& str, const char* from, const char* to)
{
string ret;
ret.reserve(str.length());
size_t from_len = 0;
while (from[from_len]) {
from_len++;
}
size_t start_pos = 0, pos;
while ((pos = str.find(from, start_pos)) != string::npos) {
ret += str.substr(start_pos, pos - start_pos);
ret += to;
pos += from_len;
start_pos = pos;
}
ret += str.substr(start_pos);
return ret;
}
int run_server(int port, const vector<char>& syntax, const vector<char>& source)
{
Server svr;
svr.Get("/", [&](const Request& /*req*/, Response& res) {
indexHTML = replace_all(indexHTML, "{{syntax}}", string(syntax.data(), syntax.size()).c_str());
indexHTML = replace_all(indexHTML, "{{source}}", string(source.data(), source.size()).c_str());
res.set_content(indexHTML, "text/html");
});
svr.Post("/parse", [](const Request& req, Response& res) {
const auto& grammarText = req.get_param_value("grammar");
string grammarResult;
string codeResult;
string astResult;
string astResultOptimized;
peg::parser peg;
auto ret = parse_grammar(grammarText, peg, grammarResult);
if (ret && peg) {
const auto& codeText = req.get_param_value("code");
shared_ptr<peg::Ast> ast;
if (parse_code(codeText, peg, codeResult, ast)) {
astResult = escape_json(peg::ast_to_s(ast));
astResultOptimized = escape_json(peg::ast_to_s(peg::AstOptimizer(true).optimize(ast)));
}
}
string json;
json += "{";
json += "\"grammar\":" + grammarResult;
if (!codeResult.empty()) {
json += ",\"code\":" + codeResult;
json += ",\"ast\":\"" + astResult + "\"";
json += ",\"astOptimized\":\"" + astResultOptimized + "\"";
}
json += "}";
res.set_content(json, "application/json");
});
svr.set_error_handler([](const Request& /*req*/, Response& res) {
const char* fmt = "<p>Error Status: <span style='color:red;'>%d</span></p>";
char buf[BUFSIZ];
snprintf(buf, sizeof(buf), fmt, res.status);
res.set_content(buf, "text/html");
});
cerr << "Server running at http://localhost:" << port << "/" << endl;
svr.listen("localhost", port);
return 0;
}
// vim: et ts=4 sw=4 cin cino={1s ff=unix