Skip to content

Instantly share code, notes, and snippets.

@prozacgod
Forked from francoishill/README.md
Created April 3, 2019 16:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save prozacgod/5a6f3f9829c16bcf093bd227a27cfa26 to your computer and use it in GitHub Desktop.
Save prozacgod/5a6f3f9829c16bcf093bd227a27cfa26 to your computer and use it in GitHub Desktop.
PEG Grammar for Command Line Parsing

Command Line Parsing Grammar

This grammar allows you to parse command lines for program execution into their various components - specifically: environment variables, the executable itself and any arguments passed to the executable.

It will take an input like the following:

ENV_X=true ENV_Y="yes please" ./test/my_exec arg1 -f1 "arg with spaces" 'another arg' --flag2 yet\ another\ arg --flag=10

And transform it into an object which can be used to start the specified program in the correct environment, with the correct arguments.

{
   "env": [
      "ENV_X=true",
      "ENV_Y=yes please"
   ],
   "exec": "./test/my_exec",
   "args": [
      "arg1",
      "-f1",
      "arg with spaces",
      "another arg",
      "--flag2",
      "yet another arg",
      "--flag=10"
   ]
}

This grammar places particular emphasis on matching Bash's environment escaping behaviour so that users familiar with invoking commands via a command line should be able to make use of systems with this grammar.

/*
* Command Line Execution Grammar
*/
Expression
= env:(EnvironmentVariable _)* exec:Executable args:(_ Argument)* _ Comment? {
return {
"env": env.map(function(t) { return t[0]; }),
"exec": exec,
"args": args.map(function(t) { return t[1]; })
};
}
EnvironmentVariable "environment variable"
= name:EnvironmentVariableKey "=" value:String {
return name + "=" + value;
}
EnvironmentVariableKey "environment variable key"
= [A-Z][A-Z0-9_]* {
return text()
}
Executable "executable"
= exe:String {
return exe;
}
Argument "argument"
= arg:String {
return arg
}
String "string"
= qqs:DoubleQuotedString { return qqs; }
/ qs:SingleQuotedString { return qs; }
/ s:UnquotedString { return s; }
UnquotedString "unquoted string"
= chars:UnquotedChars+ {
return chars.join("");
}
UnquotedChars
= [^\0-\x20\x22\x27\x5C]
/ Escape sequence:(
" "
/ "\\"
/ "/"
/ "b" { return "\b"; }
/ "f" { return "\f"; }
/ "n" { return "\n"; }
/ "r" { return "\r"; }
/ "t" { return "\t"; }
/ "u" digits:$(HEXDIG HEXDIG HEXDIG HEXDIG) {
return String.fromCharCode(parseInt(digits, 16));
}
) { return sequence; }
Escape
= '\\'
SingleQuotedString "single quoted string"
= "'" chars:SingleQuotedStringChars* "'" {
return chars.join("")
}
SingleQuotedStringChars
= UnescapedSingleQuoteChar
/ Escape sequence:(
"'"
/ "\\"
/ "/"
/ "b" { return "\b"; }
/ "f" { return "\f"; }
/ "n" { return "\n"; }
/ "r" { return "\r"; }
/ "t" { return "\t"; }
/ "u" digits:$(HEXDIG HEXDIG HEXDIG HEXDIG) {
return String.fromCharCode(parseInt(digits, 16));
}
) { return sequence }
UnescapedSingleQuoteChar
= [^\0-\x1F\x27\x5C]
DoubleQuotedString "double quoted string"
= '"' chars:DoubleQuotedStringChars* '"' {
return chars.join("");
}
DoubleQuotedStringChars
= UnescapedDoubleQuoteChar
/ Escape sequence:(
'"'
/ "\\"
/ "/"
/ "b" { return "\b"; }
/ "f" { return "\f"; }
/ "n" { return "\n"; }
/ "r" { return "\r"; }
/ "t" { return "\t"; }
/ "u" digits:$(HEXDIG HEXDIG HEXDIG HEXDIG) {
return String.fromCharCode(parseInt(digits, 16));
}
) { return sequence }
UnescapedDoubleQuoteChar
= [^\0-\x1F\x22\x5C]
Comment
= "#" comment:.* {
return comment.join("")
}
DIGIT = [0-9]
HEXDIG = [0-9a-f]i
_ "whitespace"
= [ \t\n\r]*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment