PEG shell grammar.
This commit is contained in:
parent
7752b5f686
commit
a431a84161
|
@ -0,0 +1,7 @@
|
||||||
|
ANGUISH that which one might experience when their shell lacks a programming language
|
||||||
|
or
|
||||||
|
ANother GUIle SHell
|
||||||
|
|
||||||
|
This project aims to produce at least a POSIX compliant sh
|
||||||
|
replacement. On top of that it also intends to make scheme available
|
||||||
|
for interactive and scripting application.
|
|
@ -0,0 +1,205 @@
|
||||||
|
/* -------------------------------------------------------
|
||||||
|
The grammar symbols
|
||||||
|
------------------------------------------------------- */
|
||||||
|
%token WORD
|
||||||
|
%token ASSIGNMENT_WORD
|
||||||
|
%token NAME
|
||||||
|
%token NEWLINE
|
||||||
|
%token IO_NUMBER
|
||||||
|
|
||||||
|
|
||||||
|
/* The following are the operators mentioned above. */
|
||||||
|
|
||||||
|
|
||||||
|
%token AND_IF OR_IF DSEMI
|
||||||
|
/* '&&' '||' ';;' */
|
||||||
|
|
||||||
|
|
||||||
|
%token DLESS DGREAT LESSAND GREATAND LESSGREAT DLESSDASH
|
||||||
|
/* '<<' '>>' '<&' '>&' '<>' '<<-' */
|
||||||
|
|
||||||
|
|
||||||
|
%token CLOBBER
|
||||||
|
/* '>|' */
|
||||||
|
|
||||||
|
|
||||||
|
/* The following are the reserved words. */
|
||||||
|
|
||||||
|
|
||||||
|
%token If Then Else Elif Fi Do Done
|
||||||
|
/* 'if' 'then' 'else' 'elif' 'fi' 'do' 'done' */
|
||||||
|
|
||||||
|
|
||||||
|
%token Case Esac While Until For
|
||||||
|
/* 'case' 'esac' 'while' 'until' 'for' */
|
||||||
|
|
||||||
|
|
||||||
|
/* These are reserved words, not operator tokens, and are
|
||||||
|
recognized when reserved words are recognized. */
|
||||||
|
|
||||||
|
|
||||||
|
%token Lbrace Rbrace Bang
|
||||||
|
/* '{' '}' '!' */
|
||||||
|
|
||||||
|
|
||||||
|
%token In
|
||||||
|
/* 'in' */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------
|
||||||
|
The Grammar
|
||||||
|
------------------------------------------------------- */
|
||||||
|
%start complete_command
|
||||||
|
%%
|
||||||
|
complete_command : list separator
|
||||||
|
| list
|
||||||
|
;
|
||||||
|
list : list separator_op and_or
|
||||||
|
| and_or
|
||||||
|
;
|
||||||
|
and_or : pipeline
|
||||||
|
| and_or AND_IF linebreak pipeline
|
||||||
|
| and_or OR_IF linebreak pipeline
|
||||||
|
;
|
||||||
|
pipeline : pipe_sequence
|
||||||
|
| Bang pipe_sequence
|
||||||
|
;
|
||||||
|
pipe_sequence : command
|
||||||
|
| pipe_sequence '|' linebreak command
|
||||||
|
;
|
||||||
|
command : simple_command
|
||||||
|
| compound_command
|
||||||
|
| compound_command redirect_list
|
||||||
|
| function_definition
|
||||||
|
;
|
||||||
|
compound_command : brace_group
|
||||||
|
| subshell
|
||||||
|
| for_clause
|
||||||
|
| case_clause
|
||||||
|
| if_clause
|
||||||
|
| while_clause
|
||||||
|
| until_clause
|
||||||
|
;
|
||||||
|
subshell : '(' compound_list ')'
|
||||||
|
;
|
||||||
|
compound_list : term
|
||||||
|
| newline_list term
|
||||||
|
| term separator
|
||||||
|
| newline_list term separator
|
||||||
|
;
|
||||||
|
term : term separator and_or
|
||||||
|
| and_or
|
||||||
|
;
|
||||||
|
for_clause : For name linebreak do_group
|
||||||
|
| For name linebreak in sequential_sep do_group
|
||||||
|
| For name linebreak in wordlist sequential_sep do_group
|
||||||
|
;
|
||||||
|
name : NAME /* Apply rule 5 */
|
||||||
|
;
|
||||||
|
in : In /* Apply rule 6 */
|
||||||
|
;
|
||||||
|
wordlist : wordlist WORD
|
||||||
|
| WORD
|
||||||
|
;
|
||||||
|
case_clause : Case WORD linebreak in linebreak case_list Esac
|
||||||
|
| Case WORD linebreak in linebreak case_list_ns Esac
|
||||||
|
| Case WORD linebreak in linebreak Esac
|
||||||
|
;
|
||||||
|
case_list_ns : case_list case_item_ns
|
||||||
|
| case_item_ns
|
||||||
|
;
|
||||||
|
case_list : case_list case_item
|
||||||
|
| case_item
|
||||||
|
;
|
||||||
|
case_item_ns : pattern ')' linebreak
|
||||||
|
| pattern ')' compound_list linebreak
|
||||||
|
| '(' pattern ')' linebreak
|
||||||
|
| '(' pattern ')' compound_list linebreak
|
||||||
|
;
|
||||||
|
case_item : pattern ')' linebreak DSEMI linebreak
|
||||||
|
| pattern ')' compound_list DSEMI linebreak
|
||||||
|
| '(' pattern ')' linebreak DSEMI linebreak
|
||||||
|
| '(' pattern ')' compound_list DSEMI linebreak
|
||||||
|
;
|
||||||
|
pattern : WORD /* Apply rule 4 */
|
||||||
|
| pattern '|' WORD /* Do not apply rule 4 */
|
||||||
|
;
|
||||||
|
if_clause : If compound_list Then compound_list else_part Fi
|
||||||
|
| If compound_list Then compound_list Fi
|
||||||
|
;
|
||||||
|
else_part : Elif compound_list Then compound_list
|
||||||
|
| Elif compound_list Then compound_list else_part
|
||||||
|
| Else compound_list
|
||||||
|
;
|
||||||
|
while_clause : While compound_list do_group
|
||||||
|
;
|
||||||
|
until_clause : Until compound_list do_group
|
||||||
|
;
|
||||||
|
function_definition : fname '(' ')' linebreak function_body
|
||||||
|
;
|
||||||
|
function_body : compound_command /* Apply rule 9 */
|
||||||
|
| compound_command redirect_list /* Apply rule 9 */
|
||||||
|
;
|
||||||
|
fname : NAME /* Apply rule 8 */
|
||||||
|
;
|
||||||
|
brace_group : Lbrace compound_list Rbrace
|
||||||
|
;
|
||||||
|
do_group : Do compound_list Done /* Apply rule 6 */
|
||||||
|
;
|
||||||
|
simple_command : cmd_prefix cmd_word cmd_suffix
|
||||||
|
| cmd_prefix cmd_word
|
||||||
|
| cmd_prefix
|
||||||
|
| cmd_name cmd_suffix
|
||||||
|
| cmd_name
|
||||||
|
;
|
||||||
|
cmd_name : WORD /* Apply rule 7a */
|
||||||
|
;
|
||||||
|
cmd_word : WORD /* Apply rule 7b */
|
||||||
|
;
|
||||||
|
cmd_prefix : io_redirect
|
||||||
|
| cmd_prefix io_redirect
|
||||||
|
| ASSIGNMENT_WORD
|
||||||
|
| cmd_prefix ASSIGNMENT_WORD
|
||||||
|
;
|
||||||
|
cmd_suffix : io_redirect
|
||||||
|
| cmd_suffix io_redirect
|
||||||
|
| WORD
|
||||||
|
| cmd_suffix WORD
|
||||||
|
;
|
||||||
|
redirect_list : io_redirect
|
||||||
|
| redirect_list io_redirect
|
||||||
|
;
|
||||||
|
io_redirect : io_file
|
||||||
|
| IO_NUMBER io_file
|
||||||
|
| io_here
|
||||||
|
| IO_NUMBER io_here
|
||||||
|
;
|
||||||
|
io_file : '<' filename
|
||||||
|
| LESSAND filename
|
||||||
|
| '>' filename
|
||||||
|
| GREATAND filename
|
||||||
|
| DGREAT filename
|
||||||
|
| LESSGREAT filename
|
||||||
|
| CLOBBER filename
|
||||||
|
;
|
||||||
|
filename : WORD /* Apply rule 2 */
|
||||||
|
;
|
||||||
|
io_here : DLESS here_end
|
||||||
|
| DLESSDASH here_end
|
||||||
|
;
|
||||||
|
here_end : WORD /* Apply rule 3 */
|
||||||
|
;
|
||||||
|
newline_list : NEWLINE
|
||||||
|
| newline_list NEWLINE
|
||||||
|
;
|
||||||
|
linebreak : newline_list
|
||||||
|
| /* empty */
|
||||||
|
;
|
||||||
|
separator_op : '&'
|
||||||
|
| ';'
|
||||||
|
;
|
||||||
|
separator : separator_op linebreak
|
||||||
|
| newline_list
|
||||||
|
;
|
||||||
|
sequential_sep : ';' linebreak
|
||||||
|
| newline_list
|
||||||
|
;
|
|
@ -0,0 +1,106 @@
|
||||||
|
(use-modules (ice-9 peg))
|
||||||
|
(use-modules (ice-9 peg codegen))
|
||||||
|
(use-modules (ice-9 pretty-print))
|
||||||
|
(use-modules (ice-9 rdelim))
|
||||||
|
(use-modules (ice-9 match))
|
||||||
|
|
||||||
|
|
||||||
|
(define (remove-shell-comments s)
|
||||||
|
(string-join (map
|
||||||
|
(lambda (s)
|
||||||
|
(let* ((n (string-index s #\#)))
|
||||||
|
(if n (string-pad-right s (string-length s) #\space 0 n)
|
||||||
|
s)))
|
||||||
|
(string-split s #\newline)) "\n"))
|
||||||
|
|
||||||
|
(define (flatten lst)
|
||||||
|
(cond
|
||||||
|
((null? lst)
|
||||||
|
'())
|
||||||
|
((list? (car lst))
|
||||||
|
(append (flatten (car lst)) (flatten (cdr lst))))
|
||||||
|
(else
|
||||||
|
(cons (car lst) (flatten (cdr lst))))))
|
||||||
|
|
||||||
|
(define (sh-exec ast)
|
||||||
|
(define (sh-exec- ast)
|
||||||
|
(match ast
|
||||||
|
(('name o) o)
|
||||||
|
(('word o) o)
|
||||||
|
(('command o ...) (map sh-exec- o))
|
||||||
|
((head tail ...) (map sh-exec- (append (list head) tail)))
|
||||||
|
;;(('list o ...) (map sh-exec o))
|
||||||
|
((_ o) (sh-exec- o))
|
||||||
|
(_ #f)))
|
||||||
|
(let ((cmd (filter identity (flatten (sh-exec- ast)))))
|
||||||
|
cmd
|
||||||
|
(apply system* cmd)
|
||||||
|
))
|
||||||
|
|
||||||
|
;; insert / error at convenient location to short circuit backtracking
|
||||||
|
(define (parse input)
|
||||||
|
(define-peg-string-patterns
|
||||||
|
"script <-- (sp / linebreak)* (term (separator term)* separator?)?
|
||||||
|
term <-- pipeline (sp* (and / or) (sp / linebreak)* pipeline)*
|
||||||
|
and <-- '&&'
|
||||||
|
or <-- '||'
|
||||||
|
pipeline <-- '!'? sp* command (sp* pipe (sp / linebreak)* command)*
|
||||||
|
pipe <-- '|'
|
||||||
|
command <-- simple-command / (compound-command (sp+ io-redirect)*) / function-def
|
||||||
|
compound-command <-- brace-group / subshell / for-clause / case-clause / if-clause / while-clause / until-clause
|
||||||
|
subshell <-- '(' sp* compound-list sp* ')'
|
||||||
|
compound-list <-- (sp / linebreak)* term (separator term)* separator?
|
||||||
|
case-clause <-- 'case' sp+ word (sp / linebreak)* 'in' (sp / linebreak)* (case-item sp)* 'esac'
|
||||||
|
case-item <-- '('? sp* pattern sp* ')' (((sp / linebreak) ';;' (sp / linebreak)) / ((compound-list sp* ';;'?)? (sp / linebreak)))
|
||||||
|
pattern <-- word (sp* '|' sp* word)*
|
||||||
|
for-clause <-- 'for' sp+ identifier (sp / linebreak)+ ('in' (sp+ word)* sp* sequential-sep)? do-group
|
||||||
|
do-group <-- 'do' compound-list 'done'
|
||||||
|
if-clause <-- 'if' compound-list 'then' compound-list else-part? 'fi'
|
||||||
|
else-part <-- ('elif' compound-list 'then' compound-list else-part?) / ('else' compound-list)
|
||||||
|
while-clause <-- 'while' compound-list do-group
|
||||||
|
until-clause <-- 'until' compound-list do-group
|
||||||
|
function-def <-- name sp* '(' sp* ')' (sp / linebreak)* function-body
|
||||||
|
function-body <-- compound-command io-redirect*
|
||||||
|
brace-group <-- '{' sp* compound-list sp* '}'
|
||||||
|
simple-command <-- (io-redirect sp+)* !reserved word (sp+ (io-redirect / (!reserved word)))*
|
||||||
|
xsimple-command <-- !reserved ((cmd-prefix (sp+ cmd-suffix)?) / (word (sp+ cmd-suffix)?))
|
||||||
|
reserved < ('if' / 'then' / 'else' / 'elif' / 'fi' / 'for' / 'done' / 'do' / 'until' / 'while') (sp / linebreak)
|
||||||
|
cmd-prefix <-- (io-redirect (sp* io-redirect)*) / (word (sp+ word)*)
|
||||||
|
cmd-suffix <-- (io-redirect (sp* io-redirect)*) / (word (sp+ word)*)
|
||||||
|
io-redirect <-- [0-9]* sp* (io-here / io-file)
|
||||||
|
io-file <-- ('<&' / '>&' / '>>' / '>' / '<>'/ '<' / '>|') sp* ([0-9]+ / filename)
|
||||||
|
filename <-- word
|
||||||
|
io-here <-- ('<<' / '<<-') sp* word
|
||||||
|
name <-- identifier
|
||||||
|
identifier <-- [_a-zA-Z][_a-zA-Z0-9]*
|
||||||
|
word <-- test / substitution / assignment / literal
|
||||||
|
test <-- ltest (!' ]' .)* rtest
|
||||||
|
ltest < '[ '
|
||||||
|
rtest < ' ]'
|
||||||
|
substitution <-- ('$' '(' script ')') / ('`' word (sp+ word)* '`')
|
||||||
|
assignment <-- name assign word?
|
||||||
|
assign < '='
|
||||||
|
literal <- (subst / delim / (![0-9] (!sp !linebreak ![;&|$()=] .)+) / ([0-9]+ &separator)) literal*
|
||||||
|
subst <- '$' ('$' / '*' / '@' / [0-9] / identifier / ([{] (![}] .)+ [}]))
|
||||||
|
delim <- (['] (!['] .)* [']) / ([\"] (![\"] .)* [\"]) / ([`] (![`] .)* [`])
|
||||||
|
separator <-- (sp* break (sp / linebreak)*) / (sp / linebreak)+
|
||||||
|
break <-- '&' / ';'
|
||||||
|
sequential-sep <-- (semi (sp / linebreak)*) / (sp / linebreak)+
|
||||||
|
semi < ';'
|
||||||
|
linebreak < [\r\n]
|
||||||
|
sp < [\t ]")
|
||||||
|
(let ((match (match-pattern script input)))
|
||||||
|
(if (not (eq? (string-length input) (peg:end match)))
|
||||||
|
(let ((tree (peg:tree match)))
|
||||||
|
(pretty-print (peg:tree match))
|
||||||
|
(pretty-print "parse error" (current-error-port))
|
||||||
|
(pretty-print (peg:end match)))
|
||||||
|
(peg:tree match))))
|
||||||
|
|
||||||
|
|
||||||
|
;; (let* ((input (read-string (open-input-file (cadr (command-line)))))
|
||||||
|
;; (input (remove-shell-comments input))
|
||||||
|
;; (ast (parse input)))
|
||||||
|
;; (sh-exec ast))
|
||||||
|
|
||||||
|
(pretty-print (parse (remove-shell-comments (read-string (open-input-file (cadr (command-line)))))))
|
|
@ -0,0 +1,74 @@
|
||||||
|
for file in $(find * -type f)
|
||||||
|
do
|
||||||
|
if [ "${file}" != "generator.log"\
|
||||||
|
-a "${file}" != "gaiag.log"\
|
||||||
|
-a "${file}" != "${basename}.scm"\
|
||||||
|
-a "`basename ${file} .dzn`.dzn" != "${file}" ]
|
||||||
|
then
|
||||||
|
filecount=$((filecount+1))
|
||||||
|
#files[${filecount}]=${file}
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo foo 2>&1
|
||||||
|
ls -l / -1
|
||||||
|
|
||||||
|
(echo; echo)
|
||||||
|
|
||||||
|
if true
|
||||||
|
then
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
|
||||||
|
for f in foo; do echo; done
|
||||||
|
|
||||||
|
for file in *.im
|
||||||
|
do
|
||||||
|
${bin}/asd -l gen2 ${file} 2>&1 codegenerator.log || error "codegenerator gen2 failure: ${file}" codegenerator.log
|
||||||
|
done
|
||||||
|
|
||||||
|
cat foo || echo ok && echo nok
|
||||||
|
|
||||||
|
foo=$*
|
||||||
|
foo=$@
|
||||||
|
foo=$(dirname $(dirname $@))
|
||||||
|
|
||||||
|
foo || bar && baz
|
||||||
|
|
||||||
|
${bin}/generate -p componentfile.dzn > pretty.dzn 2> pretty.err && cat pretty.dzn || cat componentfile.dzn
|
||||||
|
|
||||||
|
filecount=-1
|
||||||
|
|
||||||
|
if [ "${file}" != "generator.log"\
|
||||||
|
-a "${file}" != "gaiag.log"\
|
||||||
|
-a "${file}" != "${basename}.scm"\
|
||||||
|
-a "`basename ${file} .dzn`.dzn" != "${file}" ]
|
||||||
|
then
|
||||||
|
echo
|
||||||
|
filecount=$((filecount+1))
|
||||||
|
#files[${filecount}]=${file}
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
for file in $(find * -type f)
|
||||||
|
do
|
||||||
|
echo
|
||||||
|
done
|
||||||
|
|
||||||
|
for file in $(find * -type f)
|
||||||
|
do
|
||||||
|
echo $file
|
||||||
|
done
|
||||||
|
|
||||||
|
if ls& ls; then echo foo& echo bar || echo foo; echo barf; fi
|
||||||
|
|
||||||
|
for f in foo bar; do echo; done
|
||||||
|
ls
|
||||||
|
|
||||||
|
model=$1
|
||||||
|
model=
|
||||||
|
|
||||||
|
if [ "${model}" = "" ]
|
||||||
|
then
|
||||||
|
echo
|
||||||
|
fi
|
Loading…
Reference in New Issue