Commit 08904a68 authored by rdubner's avatar rdubner

Got REDEFINES working for Levels 01 and 77, too.

parent 2d2e4f8d
......@@ -48,7 +48,7 @@
using namespace std;
// #define DUMPING
#define DUMPING
void
scan_test(const string &filename)
......@@ -308,11 +308,6 @@ main(int argc, char *argv[])
// a normalized rendition of the parsed STORAGE sections. We read that
// in, and build a COBOL identifier tree based on the various storage
// sections and the COBOL 77 01 02 03 data heirarchy.
variable_tree.ReadFromFile(params.cbl_lst);
variable_tree.BuildCanonicalName();
#if defined(DUMPING)
// variable_tree.Dump();
#endif
// Scan the .h files for working storage and local storage locations
ScanAllDotHFiles(params.c_filename.Path(),
......@@ -330,6 +325,9 @@ main(int argc, char *argv[])
cob_fields
);
variable_tree.ReadFromFile(params.cbl_lst);
variable_tree.BuildCanonicalName(cob_data);
// The f_/b_ cross reference is as complete as we know how to make it.
// Scan cob_fields, updating the parent variables and building the lookup map
cob_fields.FixLookup(cob_data);
......@@ -352,10 +350,11 @@ main(int argc, char *argv[])
// The Consolidate() routine puts them together.
variable_tree.Dump();
variable_tree.Consolidate(cob_fields);
#if defined(DUMPING)
variable_tree.Dump();
variable_tree.DumpFlatList();
//variable_tree.DumpFlatList();
#endif
// Create the .sym.c file that will be compiled and linked into the
// executable, providing the text that will become the executable's
......
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerCommandArguments>-f C:\Users\Bob\repos\cbl-gdb-samples\ref_test_2\rtest C:\Users\Bob\repos\cbl-gdb-samples\ref_test_2\rtest.cbl</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>-f C:\Users\Bob\repos\cbl-gdb-samples\ref_test_8\rtest C:\Users\Bob\repos\cbl-gdb-samples\ref_test_8\rtest.cbl</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LocalDebuggerCommandArguments>-f C:\Users\Bob\repos\cbl-gdb-samples\ref_test_2\rtest C:\Users\Bob\repos\cbl-gdb-samples\ref_test_2\rtest.cbl</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>-f C:\Users\Bob\repos\cbl-gdb-samples\ref_test_8\rtest C:\Users\Bob\repos\cbl-gdb-samples\ref_test_8\rtest.cbl</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerCommandArguments>-f C:\Users\Bob\repos\cbl-gdb-samples\ref_test_2\rtest C:\Users\Bob\repos\cbl-gdb-samples\ref_test_2\rtest.cbl</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>-f C:\Users\Bob\repos\cbl-gdb-samples\ref_test_8\rtest C:\Users\Bob\repos\cbl-gdb-samples\ref_test_8\rtest.cbl</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerCommandArguments>-f C:\Users\Bob\repos\cbl-gdb-samples\ref_test_2\rtest C:\Users\Bob\repos\cbl-gdb-samples\ref_test_2\rtest.cbl</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>-f C:\Users\Bob\repos\cbl-gdb-samples\ref_test_8\rtest C:\Users\Bob\repos\cbl-gdb-samples\ref_test_8\rtest.cbl</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
\ No newline at end of file
......@@ -209,8 +209,8 @@ public:
std::cout << std::setw(20) << "name" ;
std::cout << std::setw(20) << "storage";
std::cout << std::setw(20) << "size";
std::cout << std::setw(20) << "program_id";
std::cout << std::setw(20) << "cbl_name";
std::cout << std::setw(20) << "program_id";
std::cout << std::endl;
......@@ -221,8 +221,8 @@ public:
std::cout << std::setw(20) << symbol.name ;
std::cout << std::setw(20) << symbol.storage_type;
std::cout << std::setw(20) << symbol.size;
std::cout << std::setw(20) << symbol.program_id;
std::cout << std::setw(20) << symbol.cbl_name;
std::cout << std::setw(20) << symbol.program_id;
std::cout << std::endl;
}
std::cout << std::endl;
......@@ -541,9 +541,9 @@ public:
std::cout << std::setw(20) << "offset" ;
std::cout << std::setw(20) << "size";
std::cout << std::setw(20) << "a_name";
std::cout << std::setw(20) << "program_id";
std::cout << std::setw(20) << "parent";
std::cout << std::setw(20) << "child";
std::cout << std::setw(20) << "parent";
std::cout << std::setw(20) << "program_id";
std::cout << std::endl;
for( V_COB_FIELDS::const_iterator it = v_cob_fields.begin();
......@@ -555,9 +555,9 @@ public:
std::cout << std::setw(20) << field.offset ;
std::cout << std::setw(20) << field.size;
std::cout << std::setw(20) << field.a_name;
std::cout << std::setw(20) << field.program_id;
std::cout << std::setw(20) << field.parent;
std::cout << std::setw(20) << field.child;
std::cout << std::setw(20) << field.parent;
std::cout << std::setw(20) << field.program_id;
std::cout << std::endl;
}
std::cout << std::endl;
......
......@@ -40,7 +40,7 @@ using namespace std;
#define OR ||
VAR_NODE::VAR_NODE()
{
{
CPROFILER;
size = 0;
offset = 0;
......@@ -50,11 +50,10 @@ VAR_NODE::VAR_NODE()
is_global = false;
parent = nullptr;
birth_order = (size_t)(-1);
}
}
void
VAR_NODE::AddChild(VAR_NODE *new_node)
{
void VAR_NODE::AddChild(VAR_NODE *new_node)
{
CPROFILER;
/* Little bit of special processing in order to keep things lined up
......@@ -81,96 +80,99 @@ VAR_NODE::AddChild(VAR_NODE *new_node)
*/
if(new_node->occurs != 0) {
if(new_node->occurs != 0)
{
// Note that the size derived from .cbl.lst is being augmented. The
// field_size attribute, which will be derived from the .h files,
// and will be the size of each element of the table, is going to be
// left alone.
new_node->size *= new_node->occurs;
}
}
// Propogate the program/section from parent to child
if(!this->program.empty()) {
if(!this->program.empty())
{
new_node->program = this->program;
}
if(!this->section.empty()) {
}
if(!this->section.empty())
{
new_node->section = this->section;
}
}
// And link in the new node
new_node->parent = this;
new_node->birth_order = this->children.size();
this->children.push_back(new_node);
}
}
VARIABLE_TREE::VARIABLE_TREE()
{
{
root = new VAR_NODE;
}
}
VARIABLE_TREE::~VARIABLE_TREE()
{
{
ChopDownTheTree();
}
}
void
VARIABLE_TREE::ChopDownTheTree(VAR_NODE *node)
{
void VARIABLE_TREE::ChopDownTheTree(VAR_NODE *node)
{
CPROFILER;
if(node) {
if(node)
{
for(VVAR_NODES::iterator child=node->children.begin();
child!=node->children.end();
child++) {
child++)
{
ChopDownTheTree(*child);
}
}
delete node;
node = nullptr;
}
}
}
void
VARIABLE_TREE::ChopDownTheTree()
{
void VARIABLE_TREE::ChopDownTheTree()
{
CPROFILER;
ChopDownTheTree(root);
}
}
void
VARIABLE_TREE::FindParentOf(VVAR_NODES &parents,int level)
{
void VARIABLE_TREE::FindParentOf(VVAR_NODES &parents,int level)
{
CPROFILER;
// Eliminate parents from the back of the stack until you find one
// that's an immediate ancestor -- not a sibling, but an ancestor --
// to 'level'
while(!parents.empty()) {
if(parents.back()->level < level) {
while(!parents.empty())
{
if(parents.back()->level < level)
{
break;
}
}
parents.pop_back();
}
}
}
void
VARIABLE_TREE::ForceParent(VVAR_NODES &parents,const string &program_id)
{
void VARIABLE_TREE::ForceParent(VVAR_NODES &parents,const string &program_id)
{
CPROFILER;
// When there is only one PROGRAM-ID in a source module, GnuCOBOL 3.0
// neglects to include that name in the variables section of the .cbl.lst
// -T listing. We call this routine to make sure there is a parent
// parent when need one
if(parents.empty()) {
if(parents.empty())
{
VAR_NODE *new_node = new VAR_NODE;
new_node->program = program_id;
new_node->level = LEVEL_PROGRAM;
root->AddChild(new_node);
parents.push_back(new_node);
}
}
}
void
VARIABLE_TREE::ReadFromFile(std::ifstream &ifs)
{
void VARIABLE_TREE::ReadFromFile(std::ifstream &ifs)
{
CPROFILER;
ifs.clear();
ifs.seekg(0);
......@@ -187,25 +189,31 @@ VARIABLE_TREE::ReadFromFile(std::ifstream &ifs)
VVAR_NODES parents; // This is a stack for keeping track
// of parent nodes
bool processing = false;
for(;;) {
for(;;)
{
getline(ifs,input);
if(ifs.eof()) {
if(ifs.eof())
{
break;
}
}
if(!processing) {
if(input.size() > 4 AND input.substr(0,4) EQ "SIZE") {
if(!processing)
{
if(input.size() > 4 AND input.substr(0,4) EQ "SIZE")
{
// We have reached the beginning of the parsed variables
processing = true;
continue;
}
if(input.size() > 4 AND input.substr(0,4) EQ "LINE") {
}
if(input.size() > 4 AND input.substr(0,4) EQ "LINE")
{
vector<string>tokens = Split(input," \t");
free_form = tokens.size() EQ 2 ;
continue;
}
}
if(first_program_id.empty()) {
if(first_program_id.empty())
{
// Here's where we look for "PROGRAM-ID. <program-id>."
// Ain't simple. We need to deal with fixed and free input,
// and we need to strip out comments, and we need to ignore
......@@ -215,15 +223,18 @@ VARIABLE_TREE::ReadFromFile(std::ifstream &ifs)
// Most of the following is pure magic, and is based on the
// actual structure of the files. Just live with it.
if(free_form AND input.length() >= 8) {
if(free_form AND input.length() >= 8)
{
// Trim away the leading "dddddd "
input = input.substr(8);
}
if(!free_form AND input.length() > 80) {
}
if(!free_form AND input.length() > 80)
{
// Trim away the SEQUENCE information at column 80
input = input.substr(0,80);
}
if(!free_form AND input.length() > 9) {
}
if(!free_form AND input.length() > 9)
{
// Trim away the leading "ddddd "
input = input.substr(9);
// We should be left with a standard COBOL 72-line input
......@@ -234,75 +245,88 @@ VARIABLE_TREE::ReadFromFile(std::ifstream &ifs)
input[3] = ' ';
input[4] = ' ';
input[5] = ' ';
}
}
// We now need to eliminate anything inside of paired single-
// or double-quotes, because we don't want to be confused by
// any crap some evil programmer put in there. Probably in
// an attempt to screw me up.
bool dequoting = true;
while(dequoting) {
while(dequoting)
{
dequoting = false;
size_t nfound;
// Find and eliminate consecutive double-quotes
nfound = input.find("\"\"");
if(nfound != string::npos) {
if(nfound != string::npos)
{
dequoting = true;
input[nfound] = ' ';
input[nfound+1] = ' ';
continue;
}
}
// and consecutive single-quotes
nfound = input.find("''");
if(nfound != string::npos) {
if(nfound != string::npos)
{
dequoting = true;
input[nfound] = ' ';
input[nfound+1] = ' ';
continue;
}
}
nfound = input.find_first_of("\"'");
if(nfound != string::npos) {
if(nfound != string::npos)
{
// Eliminate everything between the quote and its
// mate:
char endquote = input[nfound];
dequoting = true;
size_t i = nfound;
while(input[i] != endquote) {
while(input[i] != endquote)
{
input[i++] = ' ';
if(i>=input.length()) {
if(i>=input.length())
{
break;
}
}
}
if(i<input.length()) {
if(i<input.length())
{
input[i++] = ' ';
}
}
continue;
}
}
}
// And now, we have to consider comments:
if(free_form) {
if(free_form)
{
size_t nfound;
// Strip off leading spaces
nfound = input.find_first_not_of(" ");
if(nfound != string::npos) {
if(nfound != string::npos)
{
input = input.substr(nfound);
}
}
// Find the *> and >>D comment types:
nfound = input.find("*>");
if(nfound != string::npos) {
if(nfound != string::npos)
{
input = input.substr(0,nfound);
}
}
nfound = input.find(">>D");
if(nfound != string::npos) {
if(nfound != string::npos)
{
input = input.substr(0,nfound);
}
}
} else {
else
{
if( input.length() >= 7
AND (
input[7-1] EQ '*'
......@@ -310,60 +334,70 @@ VARIABLE_TREE::ReadFromFile(std::ifstream &ifs)
input[7-1] EQ '/'
OR
input[7-1] EQ 'D'
) ) {
) )
{
// Ignore comment lines
input.clear();
}
}
size_t nfound = input.find("*>");
if(nfound != string::npos) {
if(nfound != string::npos)
{
input = input.substr(0,nfound);
}
}
}
// We now have input free of comments and text literals,
// so we can split what's left and look for gold:
vector<string>tokens = Split(input," \t");
size_t ntoken = 0;
if(!program_id_triggered) {
for(ntoken=0; ntoken<tokens.size(); ntoken++) {
if(!program_id_triggered)
{
for(ntoken=0; ntoken<tokens.size(); ntoken++)
{
string token = tokens[ntoken];
string lc;
for(size_t i=0; i<token.size(); i++) {
for(size_t i=0; i<token.size(); i++)
{
char s = token[i];
lc += tolower(s);
}
if(lc EQ "program-id" OR lc EQ "program-id.") {
}
if(lc EQ "program-id" OR lc EQ "program-id.")
{
// Given our comment processing and the elimination
// of text strings, the next token we see will
// be the value we need
ntoken += 1;
program_id_triggered = true;
break;
}
}
}
}
if(program_id_triggered) {
if(ntoken < tokens.size()) {
if(program_id_triggered)
{
if(ntoken < tokens.size())
{
first_program_id = tokens[ntoken];
size_t nfound = first_program_id.find(".");
if(nfound != string::npos) {
if(nfound != string::npos)
{
first_program_id =
first_program_id.substr(0,nfound);
}
}
}
}
}
}
continue;
}
}
vector<string>tokens = Split(input," \t");
if(tokens.size() EQ 0) {
if(tokens.size() EQ 0)
{
// Ignore blank lines
continue;
}
}
// At some point GLOBAL was added, which mucks up my heuristics which
// were based on a non-GLOBAL universe. Just hack it off.
......@@ -374,7 +408,8 @@ VARIABLE_TREE::ReadFromFile(std::ifstream &ifs)
// data we need in a formal way. RJD, just before version cobc 3.1 was
// released, 2020-06-26
if(tokens.size() EQ 2 AND tokens[0] EQ "PROGRAM") {
if(tokens.size() EQ 2 AND tokens[0] EQ "PROGRAM")
{
// We are starting a brand new PROGRAM section, which has the
// root as a parent:
......@@ -385,9 +420,10 @@ VARIABLE_TREE::ReadFromFile(std::ifstream &ifs)
root->AddChild(new_node);
parents.push_back(new_node);
continue;
}
}
if(tokens.size() EQ 2 AND tokens[1] EQ "SECTION") {
if(tokens.size() EQ 2 AND tokens[1] EQ "SECTION")
{
// Sections get their own node, and they have to have the
// level-00 program-id node as a parent:
ForceParent(parents,first_program_id);
......@@ -398,7 +434,7 @@ VARIABLE_TREE::ReadFromFile(std::ifstream &ifs)
parents.back()->AddChild(new_node);
parents.push_back(new_node);
continue;
}
}
VAR_NODE *new_node = new VAR_NODE;
......@@ -408,22 +444,26 @@ VARIABLE_TREE::ReadFromFile(std::ifstream &ifs)
// remove it.
vector<string>::const_iterator it = tokens.begin();
while(it != tokens.end()) {
if( *it EQ "REDEFINES" ) {
while(it != tokens.end())
{
if( *it EQ "REDEFINES" )
{
break;
}
}
it++;
}
}
if( it != tokens.end() ) {
if( it != tokens.end() )
{
// 'it' points to REDEFINES:
size_t index = it - tokens.begin();
// Get rid of the comma at the end of index-1:
size_t n = tokens[index-1].find_last_of(',');
if( n != string::npos ) {
if( n != string::npos )
{
tokens[index-1] = tokens[index-1].substr(0,n);
}
}
// Pick up the name of the referenced variable:
new_node->redefines = tokens[index+1];
......@@ -434,61 +474,72 @@ VARIABLE_TREE::ReadFromFile(std::ifstream &ifs)
tokens.erase(it1,it2);
// And now we can proceed
}
}
it = tokens.begin();
while(it != tokens.end()) {
if( *it EQ "EXTERNAL" ) {
while(it != tokens.end())
{
if( *it EQ "EXTERNAL" )
{
new_node->is_external = true;
break;
}
}
it++;
}
if( it != tokens.end() ) {
}
if( it != tokens.end() )
{
size_t index = it - tokens.begin();
vector<string>::iterator it1 = tokens.begin() + index;
vector<string>::iterator it2 = tokens.begin() + index + 1;
tokens.erase(it1,it2);
}
}
it = tokens.begin();
while(it != tokens.end()) {
if( *it EQ "GLOBAL" ) {
while(it != tokens.end())
{
if( *it EQ "GLOBAL" )
{
new_node->is_global = true;
break;
}
}
it++;
}
if( it != tokens.end() ) {
}
if( it != tokens.end() )
{
size_t index = it - tokens.begin();
vector<string>::iterator it1 = tokens.begin() + index;
vector<string>::iterator it2 = tokens.begin() + index + 1;
tokens.erase(it1,it2);
}
}
it = tokens.begin();
while(it != tokens.end()) {
if( *it EQ "OCCURS" ) {
while(it != tokens.end())
{
if( *it EQ "OCCURS" )
{
break;
}
}
it++;
}
}
if( it != tokens.end() ) {
if( it != tokens.end() )
{
// 'it' points to OCCURS:
size_t index = it - tokens.begin();
// Get rid of any comma at the end of index-1:
size_t n = tokens[index-1].find_last_of(',');
if( n != string::npos ) {
if( n != string::npos )
{
tokens[index-1] = tokens[index-1].substr(0,n);
}
}
// There are at least two possibilities
// OCCURS 4
// OCCURS 1 TO 15
if( tokens.size() > index+2 AND tokens[index+2] EQ "TO" ) {
if( tokens.size() > index+2 AND tokens[index+2] EQ "TO" )
{
// Pick up the maximum number of occurrences
new_node->occurs = STOI(tokens[index+3]);
......@@ -496,7 +547,9 @@ VARIABLE_TREE::ReadFromFile(std::ifstream &ifs)
vector<string>::iterator it1 = tokens.begin() + index;
vector<string>::iterator it2 = tokens.begin() + index + 4;
tokens.erase(it1,it2);