1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
package main
import (
"fmt"
)
//go:generate go tool yacc -o shellyacc.go -v shellyacc.log -p shyy shell.y
type ShAtomType uint8
const (
shtSpace ShAtomType = iota
shtVaruse // ${PREFIX}
shtWord //
shtOperator
shtComment // # ...
shtSubshell // $$(
)
func (t ShAtomType) String() string {
return [...]string{
"space",
"varuse",
"word",
"operator",
"comment",
"subshell",
}[t]
}
func (t ShAtomType) IsWord() bool {
switch t {
case shtVaruse, shtWord:
return true
}
return false
}
// @Beta
type ShAtom struct {
Type ShAtomType
MkText string
Quoting ShQuoting
Data interface{}
}
func NewShAtom(typ ShAtomType, text string, quoting ShQuoting) *ShAtom {
return &ShAtom{typ, text, quoting, nil}
}
func NewShAtomVaruse(text string, quoting ShQuoting, varname string, modifiers ...string) *ShAtom {
return &ShAtom{shtVaruse, text, quoting, NewMkVarUse(varname, modifiers...)}
}
func (token *ShAtom) String() string {
if token.Type == shtWord && token.Quoting == shqPlain && token.Data == nil {
return fmt.Sprintf("%q", token.MkText)
}
if token.Type == shtVaruse {
varuse := token.Data.(*MkVarUse)
return fmt.Sprintf("varuse(%q)", varuse.varname+varuse.Mod())
}
return fmt.Sprintf("ShAtom(%v, %q, %s)", token.Type, token.MkText, token.Quoting)
}
// ShQuoting describes the context in which a string appears
// and how it must be unescaped to get its literal value.
type ShQuoting uint8
const (
shqPlain ShQuoting = iota
shqDquot
shqSquot
shqBackt
shqSubsh
shqDquotBackt
shqBacktDquot
shqBacktSquot
shqSubshSquot
shqDquotBacktDquot
shqDquotBacktSquot
shqUnknown
)
func (q ShQuoting) String() string {
return [...]string{
"plain",
"d", "s", "b", "S",
"db", "bd", "bs", "Ss",
"dbd", "dbs",
"unknown",
}[q]
}
func (q ShQuoting) ToVarUseContext() vucQuoting {
switch q {
case shqPlain:
return vucQuotPlain
case shqDquot:
return vucQuotDquot
case shqSquot:
return vucQuotSquot
case shqBackt:
return vucQuotBackt
}
return vucQuotUnknown
}
// See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_10_02
type ShToken struct {
MkText string // The text as it appeared in the Makefile, after replacing `\#` with `#`
Atoms []*ShAtom
}
func NewShToken(mkText string, atoms ...*ShAtom) *ShToken {
return &ShToken{mkText, atoms}
}
func (token *ShToken) String() string {
return fmt.Sprintf("ShToken(%v)", token.Atoms)
}
func (token *ShToken) IsAssignment() bool {
return matches(token.MkText, `^[A-Za-z_]\w*=`)
}
func (token *ShToken) IsWord() bool {
return token.Atoms[0].Type.IsWord()
}
|