ragel environment parser.

This commit is contained in:
Kelvin Sherlock 2013-07-14 01:46:10 -04:00
parent 9312383433
commit 75ad0ab38c
3 changed files with 150 additions and 356 deletions

View File

@ -6,6 +6,11 @@ add_definitions(-I ${CMAKE_SOURCE_DIR}/)
set(MPW_SRC mpw.cpp mpw_io.cpp mpw_close.cpp mpw_access.cpp mpw_ioctl.cpp environ.cpp)
add_custom_command(
OUTPUT environ.cpp
COMMAND ragel -p -G2 -o environ.cpp "${CMAKE_CURRENT_SOURCE_DIR}/environ.rl"
MAIN_DEPENDENCY environ.rl
)
add_library(MPW_LIB ${MPW_SRC})

View File

@ -1,356 +0,0 @@
/* Generated by re2c 0.13.5 on Sat May 18 16:26:02 2013 */
#include <string>
#include <unordered_map>
#include <cstdio>
/*
* #...comment
* var=value
* where value may contain $var and ${var} interpolations.
*
*/
namespace MPW {
std::string EvalString(std::string &s, std::unordered_map<std::string, std::string> &env)
{
std::string rv;
const char *cp = s.c_str();
const char *marker = NULL;
while (*cp)
{
const char *begin = cp;
{
char yych;
yych = (char)*cp;
switch (yych) {
case '\n': goto yy5;
case '$': goto yy2;
default: goto yy4;
}
yy2:
yych = (char)*(marker = ++cp);
switch (yych) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
case '_':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z': goto yy9;
case '{': goto yy7;
default: goto yy3;
}
yy3:
{
rv.push_back(*begin);
continue;
}
yy4:
yych = (char)*++cp;
goto yy3;
yy5:
++cp;
{
break;
}
yy7:
yych = (char)*++cp;
switch (yych) {
case '}': goto yy8;
default: goto yy13;
}
yy8:
cp = marker;
goto yy3;
yy9:
++cp;
yych = (char)*cp;
switch (yych) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
case '_':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z': goto yy9;
default: goto yy11;
}
yy11:
{
std::string tmp(begin + 1, cp);
// lookup value...
// append to rv.
auto iter = env.find(tmp);
if (iter != env.end())
{
rv.append(iter->second);
}
continue;
}
yy12:
++cp;
yych = (char)*cp;
yy13:
switch (yych) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
case '_':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z': goto yy12;
case '}': goto yy14;
default: goto yy8;
}
yy14:
++cp;
{
std::string tmp(begin + 2, cp - 1);
auto iter = env.find(tmp);
if (iter != env.end())
{
rv.append(iter->second);
}
continue;
}
}
}
return rv;
}
void LoadEnvironment(std::string &envfile, std::unordered_map<std::string, std::string> &env)
{
FILE *fp;
fp = fopen(envfile.c_str(), "r");
if (!fp) return;
for (;;)
{
char *begin;
char *end;
char *iter;
size_t length;
begin = fgetln(fp, &length);
if (!begin) break; // eof or error.
if (!length) continue;
if (begin[0] == '#') continue;
while (length && isspace(begin[length - 1])) --length;
if (!length) continue;
// key=value
// ehh, this could really check for [A-Za-z0-9_]+ '='
end = begin + length;
iter = std::find(begin, end, '=');
if (iter == end || iter == begin)
{
fprintf(stderr, "Invalid Environment entry: %.*s\n", (int)length, begin);
continue;
}
std::string key(begin, iter);
std::string value(iter + 1, end);
value = EvalString(value, env);
//fprintf(stdout, "%s = %s\n", key.c_str(), value.c_str());
// todo -- does this replace an existing value?
env.emplace(key, value);
}
fclose(fp);
}
}

145
mpw/environ.rl Normal file
View File

@ -0,0 +1,145 @@
%%{
machine lexer;
ws = [ \t\r\n];
word = [A-Za-z0-9_];
action emplace {
//printf("emplacing %s\n", name.c_str());
// trim any whitespace.
while (value.length() && isspace(value.back()))
value.pop_back();
env[std::move(name)] = std::move(value);
}
action error {
fprintf(stderr, "Bad environment: %.*s\n", (int)length, line);
}
value := |*
'$' word+ => {
std::string name(ts + 1, te);
auto iter = env.find(name);
if (iter != env.end())
value.append(iter->second);
};
'${' word+ '}' => {
std::string name(ts + 2, te - 1);
auto iter = env.find(name);
if (iter != env.end())
value.append(iter->second);
};
'$$' => {
value.push_back('$');
};
any $eof(emplace) => {
value.push_back(fc);
} ;
*|;
# exit w/ cs = lexer_en_comment.
comment := any* ${ fbreak; };
assignment =
word+ ${ name.push_back(fc); }
ws* %eof(error)
'='
ws*
(any - ws)? ${ fhold; fgoto value; }
%eof(emplace)
;
main := ws* ( '#' ${ fgoto comment; } | assignment);
}%%
#include <string>
#include <unordered_map>
#include <cstdio>
#include <cctype>
namespace MPW {
void LoadEnvironment(std::string &envfile, std::unordered_map<std::string, std::string> &env)
{
%% write data;
FILE *fp;
fp = fopen(envfile.c_str(), "r");
if (!fp) return;
for(;;)
{
const char *line;
size_t length;
line = fgetln(fp, &length);
if (!line) break; // eof or error.
// strip any trailign space.
while (length && isspace(line[length - 1]))
length--;
std::string name;
std::string value;
const char *p = line;
const char *pe = line + length;
const char *eof = line + length;
const char *te;
const char *ts;
int cs, act;
%%write init;
%%write exec;
if (cs == lexer_error)
{
fprintf(stderr, "Bad environment: %.*s\n", (int)length, line);
continue;
}
}
fclose(fp);
}
} // namespace
#ifdef TEST
int main(int argc, char **argv)
{
for (int i = 1; i < argc; ++i)
{
std::unordered_map<std::string, std::string> env;
std::string f(argv[i]);
MPW::LoadEnvironment(f, env);
for (const auto &kv : env)
{
printf("%s -> %s\n", kv.first.c_str(), kv.second.c_str());
}
}
return 0;
}
#endif