1
0
Fork 0
penny/sh.bnf

224 lines
7.7 KiB
BNF

!whitespace : ' ' | '\t' | '\n' | '\r' ;
_letter : 'a'-'z' 'A'-'Z' ;
_digit : '0'-'9' ;
number : _digit {_digit} ;
word /*BAD*/ : _letter {_letter | '_'} ;
nothing : . ;
name : ( _letter | '_' ) { _letter | '_' | _digit } ;
<< import "github.com/localhots/penny/ast" >>
/* Tokens */
Word
: word << ast.NewWord($0) >>
;
IoNumber
: number << ast.NewIoNumber($0) >>
;
/* Commands */
/*
CompleteCommand
: List Separator
| List
;
*/
AssignmentWord
: Word "=" Word << ast.NewAssignment($0, $2) >>
;
List
: List SeparatorOp AndOr << ast.AppendToList($0, $2) >>
| AndOr << ast.NewList($0) >>
;
AndOr
: Pipeline << ast.NewAndOr($0) >>
| AndOr "&&" Linebreak Pipeline << ast.AppendAnd($0, $3) >>
| AndOr "||" Linebreak Pipeline << ast.AppendOr($0, $3) >>
;
Pipeline
: PipeSequence << ast.NewPipeline($1, false) >>
| "!" PipeSequence << ast.NewPipeline($1, true) >>
;
PipeSequence
: Command << ast.NewPipeSequence($0) >>
| PipeSequence "|" Linebreak Command << ast.AppendToPipeSequence($0, $3) >>
;
Command
: SimpleCommand << ast.NewCommand($0, nil) >>
| CompoundCommand << ast.NewCommand($0, nil) >>
| CompoundCommand RedirectList << ast.NewCommand($0, $1) >>
| FunctionDefinition << ast.NewCommand($0, nil) >>
;
CompoundCommand
: BraceGroup << ast.NewCompoundCommand($0) >>
| Subshell << ast.NewCompoundCommand($0) >>
| ForClause << ast.NewCompoundCommand($0) >>
| CaseClause << ast.NewCompoundCommand($0) >>
| IfClause << ast.NewCompoundCommand($0) >>
| WhileClause << ast.NewCompoundCommand($0) >>
| UntilClause << ast.NewCompoundCommand($0) >>
;
Subshell
: "(" CompoundList ")" << ast.NewSubshell($1) >>
;
CompoundList
: Term << ast.NewCompoundList($0, nil) >>
| NewlineList Term << ast.NewCompoundList($1, $2) >>
| Term Separator << ast.NewCompoundList($0, $1) >>
| NewlineList Term Separator << ast.NewCompoundList($1, $2) >>
;
Term
: Term Separator AndOr << ast.AppendToTerm($0, $2, $1) >>
| AndOr << ast.NewTerm($0) >>
;
ForClause
: "for" Name Linebreak DoGroup << ast.NewForClause($1, ast.Wordlist{}, $3) >>
| "for" Name Linebreak "in" SequentialSep DoGroup << ast.NewForClause($1, ast.Wordlist{}, $5) >>
| "for" Name Linebreak "in" Wordlist SequentialSep DoGroup << ast.NewForClause($1, $4, $6) >>
;
Name
: name << ast.NewName($0) >> /* Apply rule 5 */
;
Wordlist
: Wordlist Word << ast.AppendToWordlist($0, $1) >>
| Word << ast.NewWordlist($0) >>
;
CaseClause
: "case" Word Linebreak "in" Linebreak CaseList "esac" << ast.NewCaseClause($1, $5) >>
| "case" Word Linebreak "in" Linebreak CaseListNs "esac" << ast.NewCaseClause($1, $5) >>
| "case" Word Linebreak "in" Linebreak "esac" << ast.NewCaseClause($1, ast.CaseList{}) >>
;
CaseListNs
: CaseList CaseItemNs << ast.AppendToCaseList($0, $1) >>
| CaseItemNs << ast.NewCaseList($0) >>
;
CaseList
: CaseList CaseItem << ast.AppendToCaseList($0, $1) >>
| CaseItem << ast.NewCaseList($0) >>
;
CaseItemNs
: Pattern ")" Linebreak << ast.NewCaseItem($0, nil) >>
| Pattern ")" CompoundList Linebreak << ast.NewCaseItem($0, $2) >>
| "(" Pattern ")" Linebreak << ast.NewCaseItem($1, nil) >>
| "(" Pattern ")" CompoundList Linebreak << ast.NewCaseItem($1, $3) >>
;
CaseItem
: Pattern ")" Linebreak ";;" Linebreak << ast.NewCaseItem($0, nil) >>
| Pattern ")" CompoundList ";;" Linebreak << ast.NewCaseItem($0, $2) >>
| "(" Pattern ")" Linebreak ";;" Linebreak << ast.NewCaseItem($1, nil) >>
| "(" Pattern ")" CompoundList ";;" Linebreak << ast.NewCaseItem($1, $3) >>
;
Pattern
: Word << ast.NewPattern($0) >> /* Apply rule 4 */
| Pattern "|" Word << ast.AppendToPattern($0, $2) >> /* Do not apply rule 4 */
;
IfClause
: "if" CompoundList "then" CompoundList ElsePart "fi" << ast.NewIfClause($1, $3, $4) >>
| "if" CompoundList "then" CompoundList "fi" << ast.NewIfClause($1, $3, nil) >>
;
ElsePart
: "elif" CompoundList "then" ElsePart << ast.NewIfClause($1, nil, $3) >>
| "else" CompoundList << ast.NewIfClause(nil, $1, nil) >>
;
WhileClause
: "while" CompoundList DoGroup << ast.NewWhileClause($1, $2) >>
;
UntilClause
: "until" CompoundList DoGroup << ast.NewUntilClause($1, $2) >>
;
FunctionDefinition
: FunctionName "(" ")" Linebreak FunctionBody << ast.NewFunctionDefinition($0, $4) >>
;
FunctionBody
: CompoundCommand << ast.NewFunctionBody($0, ast.RedirectList{}) >> /* Apply rule 9 */
| CompoundCommand RedirectList << ast.NewFunctionBody($0, $1) >> /* Apply rule 9 */
;
FunctionName
: Word << ast.NewFunctionName($0) >> /* Apply rule 8 */
;
BraceGroup
: "{" CompoundList "}" << ast.NewBraceGroup($1) >>
;
DoGroup
: "do" CompoundList "done" << ast.NewDoGroup($1) >> /* Apply rule 6 */
;
SimpleCommand
: CmdPrefix CmdWord CmdSuffix << ast.NewSimpleCommand($0, nil, $1, $2) >>
| CmdPrefix CmdWord << ast.NewSimpleCommand($0, nil, $1, nil) >>
| CmdPrefix << ast.NewSimpleCommand($0, nil, nil, nil) >>
| CmdName CmdSuffix << ast.NewSimpleCommand(nil, $0, nil, $1) >>
| CmdName << ast.NewSimpleCommand(nil, $0, nil, nil) >>
;
CmdName
: Word << ast.NewCmdName($0) >> /* Apply rule 7a */
;
CmdWord
: Word << ast.NewCmdWord($0) >> /* Apply rule 7b */
;
CmdPrefix
: IoRedirect << ast.NewCmdPrefix(nil, $0, nil) >>
| CmdPrefix IoRedirect << ast.NewCmdPrefix(nil, $1, $0) >>
| AssignmentWord << ast.NewCmdPrefix($0, nil, nil) >>
| CmdPrefix AssignmentWord << ast.NewCmdPrefix($1, nil, $0) >>
;
CmdSuffix
: IoRedirect << ast.NewCmdSuffix(ast.Word(""), $0, nil) >>
| CmdSuffix IoRedirect << ast.NewCmdSuffix(ast.Word(""), $1, $0) >>
| Word << ast.NewCmdSuffix($0, nil, nil) >>
| CmdSuffix Word << ast.NewCmdSuffix($1, nil, $0) >>
;
RedirectList
: IoRedirect << ast.NewRedirectList($0) >>
| RedirectList IoRedirect << ast.AppendToRedirectList($0, $1) >>
;
IoRedirect
: IoFile << ast.NewIoRedirect($0, ast.IoNumber(0), nil) >>
| IoNumber IoFile << ast.NewIoRedirect($1, $0, nil) >>
| IoHere << ast.NewIoRedirect(nil, ast.IoNumber(0), $0) >>
| IoNumber IoHere << ast.NewIoRedirect(nil, $0, $1) >>
;
IoFile
: "<" Filename << ast.NewIoFile($1, ast.R_STDIN) >>
| "<&" Filename << ast.NewIoFile($1, ast.R_INFD) >>
| ">" Filename << ast.NewIoFile($1, ast.R_STDOUT) >>
| ">&" Filename << ast.NewIoFile($1, ast.R_OUTFD) >>
| ">>" Filename << ast.NewIoFile($1, ast.R_APPEND) >>
| "<>" Filename << ast.NewIoFile($1, ast.R_ORWFD) >>
| ">|" Filename << ast.NewIoFile($1, ast.R_OUTSP) >>
;
Filename
: Word << ast.NewFilename($0) >> /* Apply rule 2 */
;
IoHere
: "<<" HereEnd << ast.NewIoHere($1, false) >>
| "<<-" HereEnd << ast.NewIoHere($1, true) >>
;
HereEnd
: Word << ast.NewHereEnd($0) >> /* Apply rule 3 */
;
NewlineList
: "\n"
| NewlineList "\n"
;
Linebreak
: NewlineList
| nothing
;
SeparatorOp
: "&" << ast.S_AMP, nil >>
| ";" << ast.S_SEMICOLON, nil >>
;
Separator
: SeparatorOp Linebreak << ast.NewSeparator($0) >>
| NewlineList
;
SequentialSep
: ";" Linebreak
| NewlineList
;