asm-parse.yy.gen.py 7.26 KB
Newer Older
1
#!/usr/bin/env python3
Benoit Perrot's avatar
Benoit Perrot committed
2
##
Benoit Perrot's avatar
Benoit Perrot committed
3
## This file is part of Nolimips, a MIPS simulator with unlimited registers
4
## Copyright (C) 2003, 2004, 2006, 2012, 2015 Benoit Perrot <benoit@lrde.epita.fr>
Benoit Perrot's avatar
Benoit Perrot committed
5
##
Benoit Perrot's avatar
Benoit Perrot committed
6
## Nolimips is free software; you can redistribute it and/or modify
Benoit Perrot's avatar
Benoit Perrot committed
7
8
9
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
10
##
Benoit Perrot's avatar
Benoit Perrot committed
11
## Nolimips is distributed in the hope that it will be useful,
Benoit Perrot's avatar
Benoit Perrot committed
12
13
14
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
15
##
Benoit Perrot's avatar
Benoit Perrot committed
16
## You should have received a copy of the GNU General Public License
17
## along with Nolimips.  If not, see <http://www.gnu.org/licenses/>.
Benoit Perrot's avatar
Benoit Perrot committed
18
##
19

Benoit Perrot's avatar
Benoit Perrot committed
20
import sys, os
21
22
import string, re

Benoit Perrot's avatar
Benoit Perrot committed
23
import nolimips
24
from nolimips import depth, define_id
25

Benoit Perrot's avatar
Benoit Perrot committed
26
#### Nolimips' Bison assembly parser generator -------------
Benoit Perrot's avatar
Benoit Perrot committed
27

Benoit Perrot's avatar
Benoit Perrot committed
28
if __name__ != "__main__" or len(sys.argv) != 2:
29
  print ("Usage: .. SRCDIR")
Benoit Perrot's avatar
Benoit Perrot committed
30
31
32
  sys.exit(1)
srcdir = sys.argv[1]

Benoit Perrot's avatar
Benoit Perrot committed
33
parser = nolimips.InstructionSetParser()
34
35
instructions = parser.parse(sys.stdin)

36
sys.stdout = open("asm-parse.yy.tmp", "w")
Benoit Perrot's avatar
Benoit Perrot committed
37

38
## Prologue --------------------------
39
40
41
42
print ("%{                                                       // -*- C++ -*-")
print (nolimips.license)
print (nolimips.generated_by_hand)
print ("""
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <string>

#include \"common.hh\"

#include \"inst/label.hh\"
#include \"inst/program_builder.hh\"
#include \"inst/exp.hh\"
#include \"inst/register.hh\"
#include \"inst/all.hh\"

#include \"parse/libparse.hh\"

using namespace inst;
%}

58
%require "3.0"
59
%skeleton "lalr1.cc"
Etienne Renault's avatar
Etienne Renault committed
60
%define parse.error verbose
61
%defines
62
63
%debug

Benoit Perrot's avatar
Benoit Perrot committed
64
65
66
67
68
69
70
71
72
73
%locations

%parse-param { std::string &filename }
%parse-param { inst::ProgramBuilder &program_builder }

%initial-action
{
  @$.begin.filename = @$.end.filename = &filename;
}

74
75
%union
{
76
77
78
  int                   i;
  std::string           *s;
  misc::unique_string   *id;
79
80
81
82
83
84
85
86
  inst::Label           *label;
  inst::Register        *reg;
  inst::Exp             *exp;
}
%{
#include \"parse/asm-scan.hh\"
%}

87
88
%token <id> LABEL               \"label\"
%token <id> LABEL_DEF           \"label definition\"
89
90
91
%token <i> INTEGER              \"integer\"
%token <s> STRING               \"string\"
%token <reg> REGISTER           \"register\"
Benoit Perrot's avatar
Benoit Perrot committed
92
93
94

%destructor { delete $$; } \"string\"

95
96
97
%destructor { delete $$; } \"label\"
%destructor { delete $$; } \"label definition\"

Benoit Perrot's avatar
Benoit Perrot committed
98
99
100
%printer { debug_stream () << *$$; } \"string\" \"register\"
%printer { debug_stream () << $$; } \"integer\"

101
102
%type <exp> exp

103
104
105
106
%token YYEOF            0 \"end of file\"
%token LPAREN           \"(\"
%token RPAREN           \")\"
%token COMMA            \",\"
107
108
109
110
111
112
113

%left EXP_ADD EXP_SUB
%left EXP_MUL EXP_DIV
%nonassoc EXP_UMINUS

%token DIR_TEXT         \".text\"
%token DIR_DATA         \".data\"
Benoit Perrot's avatar
Benoit Perrot committed
114

115
%token DIR_SPACE        \".space\"
Benoit Perrot's avatar
Benoit Perrot committed
116
117
%token DIR_BYTE         \".byte\"
%token DIR_HALF         \".half\"
118
%token DIR_WORD         \".word\"
Benoit Perrot's avatar
Benoit Perrot committed
119
%token DIR_ASCII        \".ascii\"
120
%token DIR_ASCIIZ       \".asciiz\"
121
""")
122

123
for i in instructions:
124
  print ("%token " + define_id(i.opcode) + '\t\t"' + i.opcode + '"')
125

126
print ("""
127

128
129
%start program
%%
130
//
131
132
133
134
135
136
137
138
139
140
141
142
143
144
program
:
| program DIR_TEXT instructions
| program DIR_DATA datas


// Data definitions
datas
:
| datas data

data
// Label
:  LABEL_DEF
Benoit Perrot's avatar
Benoit Perrot committed
145
{ program_builder.define_data_label(*$1); }
Benoit Perrot's avatar
Benoit Perrot committed
146
147

// Uninitialized space
148
| DIR_SPACE INTEGER
Benoit Perrot's avatar
Benoit Perrot committed
149
150
{ program_builder.add_space($2); }

151
// Values
Benoit Perrot's avatar
Benoit Perrot committed
152
153
154
155
156
157
| DIR_BYTE INTEGER
{ program_builder.add_byte($2); }

| DIR_HALF INTEGER
{ program_builder.add_half($2); }

158
| DIR_WORD INTEGER
Benoit Perrot's avatar
Benoit Perrot committed
159
{ program_builder.add_word($2); }
160
| DIR_WORD LABEL
Benoit Perrot's avatar
Benoit Perrot committed
161
{ program_builder.add_word(new LabelExp(*$2)); }
Benoit Perrot's avatar
Benoit Perrot committed
162
163
164

| DIR_ASCII STRING
{ program_builder.add_ascii($2); }
165
| DIR_ASCIIZ STRING
Benoit Perrot's avatar
Benoit Perrot committed
166
{ program_builder.add_asciiz($2); }
167
168
169
170
171
172
173
174
175

// Instruction definitions
instructions
:
| instructions instruction

instruction
// Label
: LABEL_DEF
Benoit Perrot's avatar
Benoit Perrot committed
176
{ program_builder.define_inst_label(*$1); }
177

178
// Opcodes""")
179

Benoit Perrot's avatar
Benoit Perrot committed
180
181
182
## Body ------------------------------
tokid_map = {
  "register" : "REGISTER",
183
  "immediate": "exp",
Benoit Perrot's avatar
Benoit Perrot committed
184
185
186
  "label"    : "exp",
  "address"  : "REGISTER",
  "hidden"   : ""
187
188
  }

Benoit Perrot's avatar
Benoit Perrot committed
189

190
191
192
for inst in instructions:
  for syntax in inst.syntaxes:

Benoit Perrot's avatar
Benoit Perrot committed
193
194
195
196
197
198
199
200
201
    ## Compute productions
    # A token is a tuple (token id, token name, token value)
    prods = [[(define_id(inst.opcode), "", "")]]
    for i, token in enumerate(syntax.tokens):
      if token.kind == "address":
        prods.append([("LPAREN", "", "")])
      if token.default != "":
        prods.append([(tokid_map[token.kind], token.name, token.value),
                      ("", token.name, token.default)])
202
      else:
Benoit Perrot's avatar
Benoit Perrot committed
203
204
205
206
        prods.append([(tokid_map[token.kind], token.name, token.value)])
      if token.kind == "address":
        prods.append([("RPAREN", "", "")])
    prods = depth(prods)
207

Benoit Perrot's avatar
Benoit Perrot committed
208
    ## Display rules and actions
209
    for prod in prods:
Benoit Perrot's avatar
Benoit Perrot committed
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230

      # Add COMMAs
      tokidx = {}
      lparen_p = False
      i = 0
      while True:
        token = prod[i]
        if token[0] != "":
          if i > 1:
            if token[0] == "LPAREN":
              lparen_p = (prod[i - 1][0] != "")
            if not lparen_p:
              prod.insert(i, ("COMMA", "", ""))
              i = i + 1
          if token[0] == "LPAREN":
            lparen_p = True
          elif token[0] == "RPAREN":
            lparen_p = False
        i = i + 1
        if i >= len(prod):
          break
231

Benoit Perrot's avatar
Benoit Perrot committed
232
233
      # Compute token indices
      tokidx = {}
234
235
      i = 0
      for token in prod:
Benoit Perrot's avatar
Benoit Perrot committed
236
        if token[0] != "":
237
          i = i + 1
Benoit Perrot's avatar
Benoit Perrot committed
238
        if token[1] != "":
239
          assert(not (token[1]) in tokidx)
Benoit Perrot's avatar
Benoit Perrot committed
240
          tokidx[token[1]] = i
241

Benoit Perrot's avatar
Benoit Perrot committed
242
243
244
      # Build rule and action
      rule = "|"
      action = "program_builder.add_"
Benoit Perrot's avatar
Benoit Perrot committed
245
246
      delete = ""
      deleted = []
247
      if syntax.alias != "":
Benoit Perrot's avatar
Benoit Perrot committed
248
        action = action + syntax.alias + "("
249
      else:
Benoit Perrot's avatar
Benoit Perrot committed
250
        action = action + inst.opcode + "("
251
252
      i = 0
      for token in prod:
Benoit Perrot's avatar
Benoit Perrot committed
253
254
255
        if token[0] != "":
          i = i + 1
          rule = rule + " " + token[0]
Benoit Perrot's avatar
Benoit Perrot committed
256
        value = "$" + str(i)
Benoit Perrot's avatar
Benoit Perrot committed
257
        if token[2] != "":
258
          value = re.sub(r"\$\{([^}]*)\}",
Benoit Perrot's avatar
Benoit Perrot committed
259
                         (lambda m: "$" + str(tokidx[m.groups(0)[0]])),
Benoit Perrot's avatar
Benoit Perrot committed
260
261
                         token[2])
        if token[0] in tokid_map.values():
262
          action = action + value + ", "
Benoit Perrot's avatar
Benoit Perrot committed
263
264
265
          if token[0] == "REGISTER" and value not in deleted:
            delete = delete + "  delete " + value + ";\n"
            deleted.append(value)
266
      action = action.rstrip(", ") + ")"
Benoit Perrot's avatar
Benoit Perrot committed
267
268

      # Dump rule and associated action
269
270
      print (rule)
      print ("{ " + action + ";\n" + delete + "}")
271
272
273


## Epilogue --------------------------
274
print ("""
275
exp:
Benoit Perrot's avatar
Benoit Perrot committed
276
277
278
279
  exp EXP_ADD  exp { $$ = new OpExp($1, OpExp::add, $3); }
| exp EXP_SUB  exp { $$ = new OpExp($1, OpExp::sub, $3); }
| exp EXP_MUL  exp { $$ = new OpExp($1, OpExp::mul, $3); }
| exp EXP_DIV  exp { $$ = new OpExp($1, OpExp::div, $3); }
280
| EXP_SUB exp %prec EXP_UMINUS
Benoit Perrot's avatar
Benoit Perrot committed
281
        { $$ = new OpExp(new IntExp(0), OpExp::sub, $2); }
282
283
| LPAREN exp RPAREN { $$ = $2; }
| INTEGER { $$ = new IntExp($1); }
Benoit Perrot's avatar
Benoit Perrot committed
284
| LABEL { $$ = new LabelExp(*$1); }
285
286
287

%%
void
Benoit Perrot's avatar
Benoit Perrot committed
288
yy::parser::error(const location &l, const std::string &msg)
289
{
Benoit Perrot's avatar
Benoit Perrot committed
290
  std::cerr << l << \": \" << msg << std::endl;
291
292
  exit_set (exit_parse);
}
293
""")
Benoit Perrot's avatar
Benoit Perrot committed
294
295
296

sys.stdout.close()
sys.stdout = sys.__stdout__
Benoit Perrot's avatar
Benoit Perrot committed
297
nolimips.lazy_overwrite(srcdir + os.sep + "asm-parse.yy", "asm-parse.yy.tmp")
Benoit Perrot's avatar
Benoit Perrot committed
298
os.remove("asm-parse.yy.tmp")