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 <string>
|
||||
#include <unordered_map>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mpw-shell.h"
|
||||
|
||||
#include "error.h"
|
||||
|
||||
%%{
|
||||
machine line_parser;
|
||||
|
||||
machine expand;
|
||||
alphtype unsigned char;
|
||||
|
||||
action push { scratch.push_back(fc); }
|
||||
action vinit { /* vinit */ ev.clear(); xcs = fcurs; fnext vstring_state; }
|
||||
action vpush { /* vpush */ ev.push_back(fc); }
|
||||
action vfinish0 { /* vfinish0 */ fnext *xcs; }
|
||||
action vfinish1 {
|
||||
/* vfinish1 */
|
||||
fnext *xcs;
|
||||
auto iter = env.find(ev);
|
||||
if (iter != env.end()) {
|
||||
const std::string &s = iter->second;
|
||||
scratch.append(s);
|
||||
}
|
||||
}
|
||||
action vfinish2 {
|
||||
/* vfinish2 */
|
||||
fnext *xcs;
|
||||
auto iter = env.find(ev);
|
||||
if (iter != env.end()) {
|
||||
// quote special chars...
|
||||
const std::string &s = iter->second;
|
||||
for (auto c : s) {
|
||||
if (c == '\'' || c == '"' ) scratch.push_back(escape);
|
||||
scratch.push_back(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
escape = 0xb6;
|
||||
ws = [ \t];
|
||||
nl = '\n';
|
||||
char = any - escape - ['"{`];
|
||||
escape_seq = escape any;
|
||||
|
||||
action push_back {
|
||||
line.push_back(fc);
|
||||
}
|
||||
action push_back_escape {
|
||||
line.push_back(escape);
|
||||
line.push_back(fc);
|
||||
}
|
||||
schar = [^'];
|
||||
sstring = ['] schar** ['];
|
||||
|
||||
|
||||
sstring =
|
||||
['] $push_back
|
||||
( (any-nl-[']) $push_back )*
|
||||
['] $push_back
|
||||
$err{
|
||||
fprintf(stderr, "### MPW Shell - 's must occur in pairs.\n");
|
||||
}
|
||||
;
|
||||
vchar = [^}] $vpush;
|
||||
vchar1 = [^{}] $vpush;
|
||||
|
||||
# same quoting logic as ' string
|
||||
vstring =
|
||||
'{'
|
||||
( (any-nl-'}') ${var.push_back(fc); } )*
|
||||
'}'
|
||||
${
|
||||
if (!var.empty()) {
|
||||
vstring0 = '}' @vfinish0;
|
||||
vstring1 = vchar1 vchar** '}' @vfinish1;
|
||||
vstring2 = '{' vchar** '}}' @vfinish2;
|
||||
|
||||
// flag to pass through vs "" ?
|
||||
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");
|
||||
}
|
||||
;
|
||||
vstring_state := (vstring0 | vstring1 | vstring2) $err(vstring_error);
|
||||
vstring = '{' $vinit;
|
||||
|
||||
echar = (escape_seq | any - escape - [`]) $epush;
|
||||
|
||||
estring1 = echar+ '`' @efinish1;
|
||||
estring2 = '`' echar* '``' @efinish2;
|
||||
|
||||
estring_state := (estring1 | estring2) $err(estring_error);
|
||||
estring = '`' $einit;
|
||||
|
||||
|
||||
# double-quoted string.
|
||||
# escape \n is ignored. others do nothing.
|
||||
dstring =
|
||||
["] $push_back
|
||||
(
|
||||
escape (
|
||||
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 :=
|
||||
(
|
||||
sstring
|
||||
|
|
||||
dstring
|
||||
|
|
||||
vstring
|
||||
|
|
||||
escape any $push_back_escape
|
||||
|
|
||||
(any-['"{]) $push_back
|
||||
)*
|
||||
;
|
||||
|
||||
dchar = escape_seq $push | estring | vstring | (any - escape - [`{"]) $push;
|
||||
dstring = ["] dchar** ["];
|
||||
|
||||
|
||||
main := (
|
||||
escape_seq $push
|
||||
| sstring $push
|
||||
| dstring
|
||||
| vstring
|
||||
| estring
|
||||
| char $push
|
||||
)**;
|
||||
|
||||
|
||||
}%%
|
||||
|
||||
|
||||
|
||||
%% 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;
|
||||
namespace {
|
||||
%% write data;
|
||||
}
|
||||
|
||||
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