|
| 1 | +/*******************************************************************\ |
| 2 | +
|
| 3 | +Module: Transition Systems for EBMC |
| 4 | +
|
| 5 | +Author: Daniel Kroening, [email protected] |
| 6 | +
|
| 7 | +\*******************************************************************/ |
| 8 | + |
| 9 | +#include "build_transition_system.h" |
| 10 | + |
| 11 | +#include <util/cmdline.h> |
| 12 | +#include <util/get_module.h> |
| 13 | +#include <util/message.h> |
| 14 | +#include <util/namespace.h> |
| 15 | +#include <util/options.h> |
| 16 | +#include <util/unicode.h> |
| 17 | + |
| 18 | +#include <langapi/language.h> |
| 19 | +#include <langapi/language_util.h> |
| 20 | +#include <langapi/mode.h> |
| 21 | +#include <trans-word-level/show_module_hierarchy.h> |
| 22 | +#include <trans-word-level/show_modules.h> |
| 23 | + |
| 24 | +#include "ebmc_error.h" |
| 25 | +#include "ebmc_language_file.h" |
| 26 | +#include "ebmc_version.h" |
| 27 | +#include "output_file.h" |
| 28 | +#include "transition_system.h" |
| 29 | + |
| 30 | +#include <fstream> |
| 31 | +#include <iostream> |
| 32 | + |
| 33 | +int preprocess(const cmdlinet &cmdline, message_handlert &message_handler) |
| 34 | +{ |
| 35 | + messaget message(message_handler); |
| 36 | + |
| 37 | + if(cmdline.args.size() != 1) |
| 38 | + { |
| 39 | + message.error() << "please give exactly one file to preprocess" |
| 40 | + << messaget::eom; |
| 41 | + return 1; |
| 42 | + } |
| 43 | + |
| 44 | + const auto &filename = cmdline.args.front(); |
| 45 | + std::ifstream infile(widen_if_needed(filename)); |
| 46 | + |
| 47 | + if(!infile) |
| 48 | + { |
| 49 | + message.error() << "failed to open input file `" << filename << "'" |
| 50 | + << messaget::eom; |
| 51 | + return 1; |
| 52 | + } |
| 53 | + |
| 54 | + auto language = get_language_from_filename(filename); |
| 55 | + |
| 56 | + if(language == nullptr) |
| 57 | + { |
| 58 | + source_locationt location; |
| 59 | + location.set_file(filename); |
| 60 | + message.error().source_location = location; |
| 61 | + message.error() << "failed to figure out type of file" << messaget::eom; |
| 62 | + return 1; |
| 63 | + } |
| 64 | + |
| 65 | + optionst options; |
| 66 | + |
| 67 | + // do -I |
| 68 | + if(cmdline.isset('I')) |
| 69 | + options.set_option("I", cmdline.get_values('I')); |
| 70 | + |
| 71 | + options.set_option("force-systemverilog", cmdline.isset("systemverilog")); |
| 72 | + |
| 73 | + // do -D |
| 74 | + if(cmdline.isset('D')) |
| 75 | + options.set_option("defines", cmdline.get_values('D')); |
| 76 | + |
| 77 | + language->set_language_options(options, message_handler); |
| 78 | + |
| 79 | + if(language->preprocess(infile, filename, std::cout, message_handler)) |
| 80 | + { |
| 81 | + message.error() << "PREPROCESSING FAILED" << messaget::eom; |
| 82 | + return 1; |
| 83 | + } |
| 84 | + |
| 85 | + return 0; |
| 86 | +} |
| 87 | + |
| 88 | +static bool parse( |
| 89 | + const cmdlinet &cmdline, |
| 90 | + const std::string &filename, |
| 91 | + ebmc_language_filest &language_files, |
| 92 | + message_handlert &message_handler) |
| 93 | +{ |
| 94 | + messaget message(message_handler); |
| 95 | + |
| 96 | + std::ifstream infile(widen_if_needed(filename)); |
| 97 | + |
| 98 | + if(!infile) |
| 99 | + { |
| 100 | + message.error() << "failed to open input file `" << filename << "'" |
| 101 | + << messaget::eom; |
| 102 | + return true; |
| 103 | + } |
| 104 | + |
| 105 | + auto &lf = language_files.add_file(filename); |
| 106 | + lf.filename = filename; |
| 107 | + lf.language = get_language_from_filename(filename); |
| 108 | + |
| 109 | + if(lf.language == nullptr) |
| 110 | + { |
| 111 | + source_locationt location; |
| 112 | + location.set_file(filename); |
| 113 | + message.error().source_location = location; |
| 114 | + message.error() << "failed to figure out type of file" << messaget::eom; |
| 115 | + return true; |
| 116 | + } |
| 117 | + |
| 118 | + languaget &language = *lf.language; |
| 119 | + |
| 120 | + optionst options; |
| 121 | + |
| 122 | + // do -I |
| 123 | + if(cmdline.isset('I')) |
| 124 | + options.set_option("I", cmdline.get_values('I')); |
| 125 | + |
| 126 | + options.set_option("force-systemverilog", cmdline.isset("systemverilog")); |
| 127 | + options.set_option("vl2smv-extensions", cmdline.isset("vl2smv-extensions")); |
| 128 | + options.set_option("warn-implicit-nets", cmdline.isset("warn-implicit-nets")); |
| 129 | + |
| 130 | + // do -D |
| 131 | + if(cmdline.isset('D')) |
| 132 | + options.set_option("defines", cmdline.get_values('D')); |
| 133 | + |
| 134 | + // do --ignore-initial |
| 135 | + if(cmdline.isset("ignore-initial")) |
| 136 | + options.set_option("ignore-initial", true); |
| 137 | + |
| 138 | + // do --initial-zero |
| 139 | + if(cmdline.isset("initial-zero")) |
| 140 | + options.set_option("initial-zero", true); |
| 141 | + |
| 142 | + language.set_language_options(options, message_handler); |
| 143 | + |
| 144 | + message.status() << "Parsing " << filename << messaget::eom; |
| 145 | + |
| 146 | + if(language.parse(infile, filename, message_handler)) |
| 147 | + { |
| 148 | + message.error() << "PARSING ERROR\n"; |
| 149 | + return true; |
| 150 | + } |
| 151 | + |
| 152 | + lf.get_modules(); |
| 153 | + |
| 154 | + return false; |
| 155 | +} |
| 156 | + |
| 157 | +bool parse( |
| 158 | + const cmdlinet &cmdline, |
| 159 | + ebmc_language_filest &language_files, |
| 160 | + message_handlert &message_handler) |
| 161 | +{ |
| 162 | + for(unsigned i = 0; i < cmdline.args.size(); i++) |
| 163 | + { |
| 164 | + if(parse(cmdline, cmdline.args[i], language_files, message_handler)) |
| 165 | + return true; |
| 166 | + } |
| 167 | + return false; |
| 168 | +} |
| 169 | + |
| 170 | +bool get_main( |
| 171 | + const cmdlinet &cmdline, |
| 172 | + message_handlert &message_handler, |
| 173 | + transition_systemt &transition_system) |
| 174 | +{ |
| 175 | + std::string top_module; |
| 176 | + |
| 177 | + if(cmdline.isset("module")) |
| 178 | + top_module = cmdline.get_value("module"); |
| 179 | + else if(cmdline.isset("top")) |
| 180 | + top_module = cmdline.get_value("top"); |
| 181 | + |
| 182 | + try |
| 183 | + { |
| 184 | + transition_system.main_symbol = |
| 185 | + &get_module(transition_system.symbol_table, top_module, message_handler); |
| 186 | + transition_system.trans_expr = |
| 187 | + to_trans_expr(transition_system.main_symbol->value); |
| 188 | + } |
| 189 | + |
| 190 | + catch(int e) |
| 191 | + { |
| 192 | + return true; |
| 193 | + } |
| 194 | + |
| 195 | + return false; |
| 196 | +} |
| 197 | + |
| 198 | +void make_next_state(exprt &expr) |
| 199 | +{ |
| 200 | + for(auto &sub_expression : expr.operands()) |
| 201 | + make_next_state(sub_expression); |
| 202 | + |
| 203 | + if(expr.id() == ID_symbol) |
| 204 | + expr.id(ID_next_symbol); |
| 205 | +} |
| 206 | + |
| 207 | +int get_transition_system( |
| 208 | + const cmdlinet &cmdline, |
| 209 | + message_handlert &message_handler, |
| 210 | + transition_systemt &transition_system) |
| 211 | +{ |
| 212 | + messaget message(message_handler); |
| 213 | + |
| 214 | + if(cmdline.isset("preprocess")) |
| 215 | + return preprocess(cmdline, message_handler); |
| 216 | + |
| 217 | + // |
| 218 | + // parsing |
| 219 | + // |
| 220 | + ebmc_language_filest language_files; |
| 221 | + |
| 222 | + if(parse(cmdline, language_files, message_handler)) |
| 223 | + return 1; |
| 224 | + |
| 225 | + if(cmdline.isset("show-parse")) |
| 226 | + { |
| 227 | + language_files.show_parse(std::cout, message_handler); |
| 228 | + return 0; |
| 229 | + } |
| 230 | + |
| 231 | + // |
| 232 | + // type checking |
| 233 | + // |
| 234 | + |
| 235 | + message.status() << "Converting" << messaget::eom; |
| 236 | + |
| 237 | + if(language_files.typecheck(transition_system.symbol_table, message_handler)) |
| 238 | + { |
| 239 | + message.error() << "CONVERSION ERROR" << messaget::eom; |
| 240 | + return 2; |
| 241 | + } |
| 242 | + |
| 243 | + if(cmdline.isset("show-modules")) |
| 244 | + { |
| 245 | + show_modules(transition_system.symbol_table, std::cout); |
| 246 | + return 0; |
| 247 | + } |
| 248 | + |
| 249 | + if(cmdline.isset("modules-xml")) |
| 250 | + { |
| 251 | + auto filename = cmdline.get_value("modules-xml"); |
| 252 | + auto outfile = output_filet{filename}; |
| 253 | + show_modules_xml(transition_system.symbol_table, outfile.stream()); |
| 254 | + return 0; |
| 255 | + } |
| 256 | + |
| 257 | + if(cmdline.isset("json-modules")) |
| 258 | + { |
| 259 | + auto out_file = output_filet{cmdline.get_value("json-modules")}; |
| 260 | + json_modules(transition_system.symbol_table, out_file.stream()); |
| 261 | + return 0; |
| 262 | + } |
| 263 | + |
| 264 | + if(cmdline.isset("show-symbol-table")) |
| 265 | + { |
| 266 | + std::cout << transition_system.symbol_table; |
| 267 | + return 0; |
| 268 | + } |
| 269 | + |
| 270 | + // get module name |
| 271 | + |
| 272 | + if(get_main(cmdline, message_handler, transition_system)) |
| 273 | + return 1; |
| 274 | + |
| 275 | + if(cmdline.isset("show-module-hierarchy")) |
| 276 | + { |
| 277 | + DATA_INVARIANT( |
| 278 | + transition_system.main_symbol != nullptr, "must have main_symbol"); |
| 279 | + show_module_hierarchy( |
| 280 | + transition_system.symbol_table, |
| 281 | + *transition_system.main_symbol, |
| 282 | + std::cout); |
| 283 | + return 0; |
| 284 | + } |
| 285 | + |
| 286 | + // --reset given? |
| 287 | + if(cmdline.isset("reset")) |
| 288 | + { |
| 289 | + namespacet ns(transition_system.symbol_table); |
| 290 | + exprt reset_constraint = to_expr( |
| 291 | + ns, transition_system.main_symbol->name, cmdline.get_value("reset")); |
| 292 | + |
| 293 | + // true in initial state |
| 294 | + transt new_trans_expr = transition_system.trans_expr; |
| 295 | + new_trans_expr.init() = and_exprt(new_trans_expr.init(), reset_constraint); |
| 296 | + |
| 297 | + // and not anymore afterwards |
| 298 | + exprt reset_next_state = reset_constraint; |
| 299 | + make_next_state(reset_next_state); |
| 300 | + |
| 301 | + new_trans_expr.trans() = |
| 302 | + and_exprt(new_trans_expr.trans(), not_exprt(reset_next_state)); |
| 303 | + transition_system.trans_expr = new_trans_expr; |
| 304 | + } |
| 305 | + |
| 306 | + return -1; // done with the transition system |
| 307 | +} |
| 308 | + |
| 309 | +transition_systemt get_transition_system( |
| 310 | + const cmdlinet &cmdline, |
| 311 | + message_handlert &message_handler) |
| 312 | +{ |
| 313 | + transition_systemt transition_system; |
| 314 | + auto exit_code = |
| 315 | + get_transition_system(cmdline, message_handler, transition_system); |
| 316 | + if(exit_code != -1) |
| 317 | + throw ebmc_errort().with_exit_code(exit_code); |
| 318 | + return transition_system; |
| 319 | +} |
| 320 | + |
| 321 | +int show_parse(const cmdlinet &cmdline, message_handlert &message_handler) |
| 322 | +{ |
| 323 | + transition_systemt dummy_transition_system; |
| 324 | + return get_transition_system( |
| 325 | + cmdline, message_handler, dummy_transition_system); |
| 326 | +} |
| 327 | + |
| 328 | +int show_modules(const cmdlinet &cmdline, message_handlert &message_handler) |
| 329 | +{ |
| 330 | + transition_systemt dummy_transition_system; |
| 331 | + return get_transition_system( |
| 332 | + cmdline, message_handler, dummy_transition_system); |
| 333 | +} |
| 334 | + |
| 335 | +int show_module_hierarchy( |
| 336 | + const cmdlinet &cmdline, |
| 337 | + message_handlert &message_handler) |
| 338 | +{ |
| 339 | + transition_systemt dummy_transition_system; |
| 340 | + return get_transition_system( |
| 341 | + cmdline, message_handler, dummy_transition_system); |
| 342 | +} |
| 343 | + |
| 344 | +int show_symbol_table( |
| 345 | + const cmdlinet &cmdline, |
| 346 | + message_handlert &message_handler) |
| 347 | +{ |
| 348 | + transition_systemt dummy_transition_system; |
| 349 | + return get_transition_system( |
| 350 | + cmdline, message_handler, dummy_transition_system); |
| 351 | +} |
0 commit comments