aboutsummaryrefslogtreecommitdiff
blob: 43f6de5a112598985b07a0cdf31264aea35ae6b9 (plain)
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
import os
from ply import lex
from ply import yacc

def scanmakefile(makefile):
    tokens = (
            "VAR",
            "COLON",
            "PERCENT",
            "TEXT",
            "DOLLAR",
            "LPAR",
            "RPAR",
            "END",
            "EQUAL",
            "ENDTAB",
            "LESS",
            )

    states = (
            ("com", "exclusive"),
            )

    def t_begin_com(t):
        r"\#"
        t.lexer.push_state("com")

    def t_com_newline(t):
        r".*\\[ \t]*\n"
        pass

    def t_com_END(t):
        r"\n"
        t.lexer.pop_state()
        return t

    def t_VAR(t):
        r"[a-zA-Z_][a-zA-Z0-9_]*[ \t]*="
        t.value = t.value.split()[0].rstrip("=") #get the name of the var
        return t

    def t_TEXT(t):
        #make sure it grabs "file-name" and "-flags"
        r"-*\.*[a-zA-Z_][-|a-zA-Z0-9_]*"
        return t

    def t_LESS(t):
        r"\$<"
        pass

    def t_DOLLAR(t):
        r"\$"
        return t

    def t_COLON(t):
        r"\:"
        return t

    def t_EQUAL(t):
        r"\="
        return t

    def t_LPAR(t):
        r"\("
        return t

    def t_RPAR(t):
        r"\)"
        return t

    def t_PERCENT(t):
        r"\%"
        return t

    def t_contline(t):
        r"\\\n"
        pass

    def t_ENDTAB(t):
        r"\n\t"
        return t

    def t_END(t):
        r"[\n]+"
        return t

    def t_ANY_error(t):
        t.lexer.skip(1)

    lexer = lex.lex()

    lexer.input(makefile)
    for tok in lexer:
        print(tok)


    #YACC begins here

    #a dict with values of defined variables
    variables = {}
    targets = [] #buildtargets, [[target,deps,options],[target2,....

    def p_target(p):
        """
        var : var textlst COLON textlst end
            | textlst COLON textlst end
            | var textlst COLON textlst options end
            | textlst COLON textlst options end
        """
        if len(p) == 6:
            if p[3] == ":":
                targets.append([p[2][0],p[4],[]])
            else:
                targets.append([p[1][0],p[3],p[4]])
        elif len(p) == 5:
            targets.append([p[1][0],p[3],[]])
        else:
            targets.append([p[2][0],p[4],p[5]])

    def p_lonetarget(p):
        """
        var : var textlst COLON options end
            | textlst COLON options end
        """
        if len(p) == 6:
            targets.append([p[2][0],[],p[4]])
        else:
            targets.append([p[1][0],[],p[3]])

    def p_depconv(p):
        """
        var : var command COLON command end
            | var command COLON command options end
        """
        if len(p) == 6:
            options = []
        else:
            options = p[5]

        if p[2][0] == p[4][0] == "%":
            for target in targets:
                for dep in target[1]:
                    if p[2][1] in dep:
                        targets.append([dep,[(dep.replace(p[2][1],p[4][1]))],options])
        else:
            print("Unknown command")

    def p_var(p):
        """
        var : VAR textlst end
            | VAR end
            | var VAR textlst end
            | var VAR end
        """
        if isinstance(p[2],list):
            variables[p[1]] = p[2]
        elif len(p) == 5:
            variables[p[2]] = p[3]
        elif len(p) == 3:
            variables[p[1]] = []
        else:
            variables[p[2]] = []

    def p_endtab(p):
        """
        options : ENDTAB textlst
                | options ENDTAB textlst
        """
        if len(p) == 3:
            p[0] = p[2]
        else:
            p[0] = p[1] + p[3]

    def p_usecom(p):
        """
        textlst : DOLLAR LPAR textlst COLON command RPAR
                | textlst DOLLAR LPAR textlst COLON command RPAR
        """
        if len(p) == 8:
            o = 1 #offset
        else:
            o = 0
        p[3+o] = variables[p[3+o][0]]
        p[0] = []
        if p[5][0] == "replace":
            for text in p[3+o]:
                p[0] += [text.replace(p[5+o][1],p[5+o][2])]
        else:
            for text in p[3+o]:
                p[0] += [text + p[5+o][1]]

    def p_textlst(p):
        """
        textlst : textlst TEXT
                | TEXT
                | DOLLAR LPAR textlst RPAR
                | textlst DOLLAR LPAR textlst RPAR
        """
        if len(p) == 2:
            p[0] = [p[1]]
        elif len(p) == 3:
            p[0] = p[1] + [p[2]]
        elif len(p) == 5:
            if p[3][0] in variables:
                var = variables[p[3][0]]
                p[0] = var
            else:
                p[0] = ["not defined"]
        else:
            if p[4][0] in variables:
                var = variables[p[4][0]]
                p[0] = p[1] + var
            else:
                p[0] = ["not defined"]

    def p_command(p):
        """
        command : TEXT EQUAL TEXT
                | PERCENT EQUAL PERCENT TEXT
                | PERCENT TEXT
        """
        if len(p) == 4:
            p[0] = ["replace", p[1], p[3]]
        elif len(p) == 5:
            p[0] = ["append", p[4]]
        else:
            p[0] = [p[1],p[2]]

    def p_end(p):
        """
        end : end END
            | END
        """

    def p_error(p):
        print("syntax error at '%s'" % p.type,p.lexpos)
        pass

    yacc.yacc()

    yacc.parse(makefile)

    for target in targets:
        print(target)
    #print(variables)


file = "/usr/portage/distfiles/svn-src/doneyet-read-only/trunk/Makefile"

with open(file, encoding="utf-8", errors="replace") as inputfile:
    scanmakefile(inputfile.read())