mirror of
https://github.com/ksherlock/mpw-shell.git
synced 2025-03-13 07:32:50 +00:00
rewrite variable expansion, add initial support for ...
command expansion.
This commit is contained in:
parent
47af010ba5
commit
fe76877693
@ -3,132 +3,131 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "mpw-shell.h"
|
#include "mpw-shell.h"
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
%%{
|
%%{
|
||||||
machine line_parser;
|
|
||||||
|
machine expand;
|
||||||
alphtype unsigned char;
|
alphtype unsigned char;
|
||||||
|
|
||||||
escape = 0xb6;
|
action push { scratch.push_back(fc); }
|
||||||
ws = [ \t];
|
action vinit { /* vinit */ ev.clear(); xcs = fcurs; fnext vstring_state; }
|
||||||
nl = '\n';
|
action vpush { /* vpush */ ev.push_back(fc); }
|
||||||
|
action vfinish0 { /* vfinish0 */ fnext *xcs; }
|
||||||
action push_back {
|
action vfinish1 {
|
||||||
line.push_back(fc);
|
/* vfinish1 */
|
||||||
}
|
fnext *xcs;
|
||||||
action push_back_escape {
|
auto iter = env.find(ev);
|
||||||
line.push_back(escape);
|
if (iter != env.end()) {
|
||||||
line.push_back(fc);
|
const std::string &s = iter->second;
|
||||||
}
|
scratch.append(s);
|
||||||
|
|
||||||
|
|
||||||
sstring =
|
|
||||||
['] $push_back
|
|
||||||
( (any-nl-[']) $push_back )*
|
|
||||||
['] $push_back
|
|
||||||
$err{
|
|
||||||
fprintf(stderr, "### MPW Shell - 's must occur in pairs.\n");
|
|
||||||
}
|
}
|
||||||
;
|
}
|
||||||
|
action vfinish2 {
|
||||||
# same quoting logic as ' string
|
/* vfinish2 */
|
||||||
vstring =
|
fnext *xcs;
|
||||||
'{'
|
auto iter = env.find(ev);
|
||||||
( (any-nl-'}') ${var.push_back(fc); } )*
|
if (iter != env.end()) {
|
||||||
'}'
|
// quote special chars...
|
||||||
${
|
const std::string &s = iter->second;
|
||||||
if (!var.empty()) {
|
for (auto c : s) {
|
||||||
|
if (c == '\'' || c == '"' ) scratch.push_back(escape);
|
||||||
// flag to pass through vs "" ?
|
scratch.push_back(c);
|
||||||
auto iter = env.find(var);
|
|
||||||
if (iter == env.end()) {
|
|
||||||
if (env.passthrough()) {
|
|
||||||
line.push_back('{');
|
|
||||||
line.append(var);
|
|
||||||
line.push_back('}');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
line.append((std::string)iter->second);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
var.clear();
|
|
||||||
}
|
}
|
||||||
$err{
|
}
|
||||||
fprintf(stderr, "### MPW Shell - {s must occur in pairs.\n");
|
|
||||||
}
|
action einit{ /* einit */ ev.clear(); xcs = fcurs; fnext estring_state; }
|
||||||
;
|
action epush{ /* epush */ ev.push_back(fc); }
|
||||||
|
action efinish1{
|
||||||
|
/* efinish1 */
|
||||||
|
fnext *xcs;
|
||||||
|
throw std::runtime_error("MPW Shell - `...` not yet supported.");
|
||||||
|
}
|
||||||
|
action efinish2{
|
||||||
|
/* efinish2 */
|
||||||
|
fnext *xcs;
|
||||||
|
throw std::runtime_error("MPW Shell - `...` not yet supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
action vstring_error{
|
||||||
|
throw vstring_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
action estring_error{
|
||||||
|
throw estring_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# double-quoted string.
|
escape = 0xb6;
|
||||||
# escape \n is ignored. others do nothing.
|
char = any - escape - ['"{`];
|
||||||
dstring =
|
escape_seq = escape any;
|
||||||
["] $push_back
|
|
||||||
(
|
schar = [^'];
|
||||||
escape (
|
sstring = ['] schar** ['];
|
||||||
nl ${ /* esc newline */ }
|
|
||||||
|
|
|
||||||
(any-nl) $push_back_escape
|
|
||||||
)
|
|
||||||
|
|
|
||||||
vstring
|
|
||||||
|
|
|
||||||
(any-escape-nl-["{]) $push_back
|
|
||||||
)* ["] $push_back
|
|
||||||
$err{
|
|
||||||
fprintf(stderr, "### MPW Shell - \"s must occur in pairs.\n");
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
main :=
|
vchar = [^}] $vpush;
|
||||||
(
|
vchar1 = [^{}] $vpush;
|
||||||
sstring
|
|
||||||
|
|
vstring0 = '}' @vfinish0;
|
||||||
dstring
|
vstring1 = vchar1 vchar** '}' @vfinish1;
|
||||||
|
|
vstring2 = '{' vchar** '}}' @vfinish2;
|
||||||
vstring
|
|
||||||
|
|
vstring_state := (vstring0 | vstring1 | vstring2) $err(vstring_error);
|
||||||
escape any $push_back_escape
|
vstring = '{' $vinit;
|
||||||
|
|
|
||||||
(any-['"{]) $push_back
|
echar = (escape_seq | any - escape - [`]) $epush;
|
||||||
)*
|
|
||||||
;
|
estring1 = echar+ '`' @efinish1;
|
||||||
|
estring2 = '`' echar* '``' @efinish2;
|
||||||
|
|
||||||
|
estring_state := (estring1 | estring2) $err(estring_error);
|
||||||
|
estring = '`' $einit;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
dchar = escape_seq $push | estring | vstring | (any - escape - [`{"]) $push;
|
||||||
|
dstring = ["] dchar** ["];
|
||||||
|
|
||||||
|
|
||||||
|
main := (
|
||||||
|
escape_seq $push
|
||||||
|
| sstring $push
|
||||||
|
| dstring
|
||||||
|
| vstring
|
||||||
|
| estring
|
||||||
|
| char $push
|
||||||
|
)**;
|
||||||
|
|
||||||
|
|
||||||
}%%
|
}%%
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
%% write data;
|
||||||
%% write data;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* has to be done separately since you can do dumb stuff like:
|
|
||||||
* set q '"' ; echo {q} dsfsdf"
|
|
||||||
*/
|
|
||||||
|
|
||||||
std::string expand_vars(const std::string &s, const Environment &env) {
|
|
||||||
|
|
||||||
if (s.find('{') == s.npos) return s;
|
|
||||||
std::string var;
|
|
||||||
std::string line;
|
|
||||||
|
|
||||||
int cs;
|
|
||||||
const unsigned char *p = (const unsigned char *)s.data();
|
|
||||||
const unsigned char *pe = (const unsigned char *)s.data() + s.size();
|
|
||||||
const unsigned char *eof = pe;
|
|
||||||
|
|
||||||
%%write init;
|
|
||||||
|
|
||||||
%%write exec;
|
|
||||||
|
|
||||||
return line;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string expand_vars(const std::string &s, const Environment &env) {
|
||||||
|
if (s.find_first_of("{`", 0, 2) == s.npos) return s;
|
||||||
|
|
||||||
|
int cs;
|
||||||
|
int xcs;
|
||||||
|
|
||||||
|
const unsigned char *p = (const unsigned char *)s.data();
|
||||||
|
const unsigned char *pe = p + s.size();
|
||||||
|
const unsigned char *eof = pe;
|
||||||
|
|
||||||
|
std::string scratch;
|
||||||
|
std::string ev;
|
||||||
|
|
||||||
|
scratch.reserve(s.size());
|
||||||
|
%% write init;
|
||||||
|
%% write exec;
|
||||||
|
|
||||||
|
return scratch;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user