Skip to content

Commit 4a83abf

Browse files
committed
copy language_file.cpp and language_file.h from CBMC
The logic implemented in CBMC's language_filest class typechecks modules starting from the leaves of the dependency tree. This is an ill-fit for both SMV and Verilog, which expect elaboration and type checking to start from the root (or "main") module. This copies the file that contains the langauge_filet and language_filest classes in order to make this change locally.
1 parent 195103b commit 4a83abf

File tree

4 files changed

+477
-4
lines changed

4 files changed

+477
-4
lines changed

src/ebmc/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ SRC = \
1212
diatest.cpp \
1313
dimacs_writer.cpp \
1414
ebmc_base.cpp \
15+
ebmc_language_file.cpp \
1516
ebmc_languages.cpp \
1617
ebmc_parse_options.cpp \
1718
ebmc_properties.cpp \

src/ebmc/ebmc_language_file.cpp

Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
/*******************************************************************\
2+
3+
Module:
4+
5+
Author: Daniel Kroening, kroening@kroening.com
6+
7+
\*******************************************************************/
8+
9+
#include "ebmc_language_file.h"
10+
11+
#include <util/message.h>
12+
13+
#include <langapi/language.h>
14+
15+
#include <fstream>
16+
17+
ebmc_language_filet::ebmc_language_filet(const ebmc_language_filet &rhs):
18+
modules(rhs.modules),
19+
language(rhs.language==nullptr?nullptr:rhs.language->new_language()),
20+
filename(rhs.filename)
21+
{
22+
}
23+
24+
/// To avoid compiler errors, the complete definition of a pointed-to type must
25+
/// be visible at the point at which the unique_ptr destructor is created. In
26+
/// this case, the pointed-to type is forward-declared, so we have to place the
27+
/// destructor in the source file, where the full definition is availible.
28+
ebmc_language_filet::~ebmc_language_filet()=default;
29+
30+
ebmc_language_filet::ebmc_language_filet(const std::string &filename)
31+
: filename(filename)
32+
{
33+
}
34+
35+
void ebmc_language_filet::get_modules()
36+
{
37+
language->modules_provided(modules);
38+
}
39+
40+
void ebmc_language_filet::convert_lazy_method(
41+
const irep_idt &id,
42+
symbol_table_baset &symbol_table,
43+
message_handlert &message_handler)
44+
{
45+
language->convert_lazy_method(id, symbol_table, message_handler);
46+
}
47+
48+
void ebmc_language_filest::show_parse(
49+
std::ostream &out,
50+
message_handlert &message_handler)
51+
{
52+
for(const auto &file : file_map)
53+
file.second.language->show_parse(out, message_handler);
54+
}
55+
56+
bool ebmc_language_filest::parse(message_handlert &message_handler)
57+
{
58+
messaget log(message_handler);
59+
60+
for(auto &file : file_map)
61+
{
62+
// open file
63+
64+
std::ifstream infile(file.first);
65+
66+
if(!infile)
67+
{
68+
log.error() << "Failed to open " << file.first << messaget::eom;
69+
return true;
70+
}
71+
72+
// parse it
73+
74+
languaget &language=*(file.second.language);
75+
76+
if(language.parse(infile, file.first, message_handler))
77+
{
78+
log.error() << "Parsing of " << file.first << " failed" << messaget::eom;
79+
return true;
80+
}
81+
82+
// what is provided?
83+
84+
file.second.get_modules();
85+
}
86+
87+
return false;
88+
}
89+
90+
bool ebmc_language_filest::typecheck(
91+
symbol_table_baset &symbol_table,
92+
const bool keep_file_local,
93+
message_handlert &message_handler)
94+
{
95+
// typecheck interfaces
96+
97+
for(auto &file : file_map)
98+
{
99+
if(file.second.language->interfaces(symbol_table, message_handler))
100+
return true;
101+
}
102+
103+
// build module map
104+
105+
unsigned collision_counter=0;
106+
107+
for(auto &file : file_map)
108+
{
109+
const ebmc_language_filet::modulest &modules=
110+
file.second.modules;
111+
112+
for(ebmc_language_filet::modulest::const_iterator
113+
mo_it=modules.begin();
114+
mo_it!=modules.end();
115+
mo_it++)
116+
{
117+
// these may collide, and then get renamed
118+
std::string module_name=*mo_it;
119+
120+
while(module_map.find(module_name)!=module_map.end())
121+
{
122+
module_name=*mo_it+"#"+std::to_string(collision_counter);
123+
collision_counter++;
124+
}
125+
126+
ebmc_language_modulet module;
127+
module.file=&file.second;
128+
module.name=module_name;
129+
module_map.insert(
130+
std::pair<std::string, ebmc_language_modulet>(module.name, module));
131+
}
132+
}
133+
134+
// typecheck files
135+
136+
for(auto &file : file_map)
137+
{
138+
if(file.second.modules.empty())
139+
{
140+
if(file.second.language->can_keep_file_local())
141+
{
142+
if(file.second.language->typecheck(
143+
symbol_table, "", message_handler, keep_file_local))
144+
return true;
145+
}
146+
else
147+
{
148+
if(file.second.language->typecheck(symbol_table, "", message_handler))
149+
return true;
150+
}
151+
// register lazy methods.
152+
// TODO: learn about modules and generalise this
153+
// to module-providing languages if required.
154+
std::unordered_set<irep_idt> lazy_method_ids;
155+
file.second.language->methods_provided(lazy_method_ids);
156+
for(const auto &id : lazy_method_ids)
157+
lazy_method_map[id]=&file.second;
158+
}
159+
}
160+
161+
// typecheck modules
162+
163+
for(auto &module : module_map)
164+
{
165+
if(typecheck_module(
166+
symbol_table, module.second, keep_file_local, message_handler))
167+
return true;
168+
}
169+
170+
return false;
171+
}
172+
173+
bool ebmc_language_filest::generate_support_functions(
174+
symbol_table_baset &symbol_table,
175+
message_handlert &message_handler)
176+
{
177+
std::set<std::string> languages;
178+
179+
for(auto &file : file_map)
180+
{
181+
if(languages.insert(file.second.language->id()).second)
182+
if(file.second.language->generate_support_functions(
183+
symbol_table, message_handler))
184+
return true;
185+
}
186+
187+
return false;
188+
}
189+
190+
bool ebmc_language_filest::final(symbol_table_baset &symbol_table)
191+
{
192+
std::set<std::string> languages;
193+
194+
for(auto &file : file_map)
195+
{
196+
if(languages.insert(file.second.language->id()).second)
197+
if(file.second.language->final(symbol_table))
198+
return true;
199+
}
200+
201+
return false;
202+
}
203+
204+
bool ebmc_language_filest::interfaces(
205+
symbol_table_baset &symbol_table,
206+
message_handlert &message_handler)
207+
{
208+
for(auto &file : file_map)
209+
{
210+
if(file.second.language->interfaces(symbol_table, message_handler))
211+
return true;
212+
}
213+
214+
return false;
215+
}
216+
217+
bool ebmc_language_filest::typecheck_module(
218+
symbol_table_baset &symbol_table,
219+
const std::string &module,
220+
const bool keep_file_local,
221+
message_handlert &message_handler)
222+
{
223+
// check module map
224+
225+
module_mapt::iterator it=module_map.find(module);
226+
227+
if(it==module_map.end())
228+
{
229+
messaget log(message_handler);
230+
log.error() << "found no file that provides module " << module
231+
<< messaget::eom;
232+
return true;
233+
}
234+
235+
return typecheck_module(
236+
symbol_table, it->second, keep_file_local, message_handler);
237+
}
238+
239+
bool ebmc_language_filest::typecheck_module(
240+
symbol_table_baset &symbol_table,
241+
ebmc_language_modulet &module,
242+
const bool keep_file_local,
243+
message_handlert &message_handler)
244+
{
245+
// already typechecked?
246+
247+
if(module.type_checked)
248+
return false;
249+
250+
messaget log(message_handler);
251+
252+
// already in progress?
253+
254+
if(module.in_progress)
255+
{
256+
log.error() << "circular dependency in " << module.name << messaget::eom;
257+
return true;
258+
}
259+
260+
module.in_progress=true;
261+
262+
// first get dependencies of current module
263+
264+
std::set<std::string> dependency_set;
265+
266+
module.file->language->dependencies(module.name, dependency_set);
267+
268+
for(std::set<std::string>::const_iterator it=
269+
dependency_set.begin();
270+
it!=dependency_set.end();
271+
it++)
272+
{
273+
module.in_progress =
274+
!typecheck_module(symbol_table, *it, keep_file_local, message_handler);
275+
if(module.in_progress == false)
276+
return true;
277+
}
278+
279+
// type check it
280+
281+
log.status() << "Type-checking " << module.name << messaget::eom;
282+
283+
if(module.file->language->can_keep_file_local())
284+
{
285+
module.in_progress = !module.file->language->typecheck(
286+
symbol_table, module.name, message_handler, keep_file_local);
287+
}
288+
else
289+
{
290+
module.in_progress = !module.file->language->typecheck(
291+
symbol_table, module.name, message_handler);
292+
}
293+
294+
if(!module.in_progress)
295+
return true;
296+
297+
module.type_checked=true;
298+
module.in_progress=false;
299+
300+
return false;
301+
}

0 commit comments

Comments
 (0)