0

I am having so much trouble trying to solve this one out. I have to read a .c file that has three functions (add, sub and main) and I want to print to the console the name of their variables with the name of the function in brackets. I tried implementing a string function_name in my struct to store the value of the functions, but I don't know how to print it next to my variables until I hit another function. Any help or advice will be much appreciated.

For example:

From this .c text

int add ( int a , int b )
{
    return a + b ;
}

I want to get this:

add, line 1, function, int, referenced 2
a (add), line 1, variable, int, referenced 1 
b (add), line 1, variable, int, referenced 1

But I get this:

add(add), line 1, function, int, referenced 16
a, line 1, variable, int, referenced 15
b, line 1, variable, int, referenced 15

My code so far looks like this.

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>

using namespace std;

struct identifier
{
    string id_name; 
    string function_name;
    int id_count; 
    string id_function;
    string id_type;
    int id_ref;

};

int main(int argc, char** argv)
{
    
    
    if (argc < 2)
    {
        cout << "ERROR: There is no file selected." << endl;
    }
    
    ifstream file(argv[1]);
    string line;
    string token;
    vector<identifier> id_list;

    int line_counter = 0;
    int num_functions = 0;
    int num_variables = 0;
    int num_if = 0;
    int num_for = 0;
    int num_while = 0;
    

    while (getline(file, line))
    {
        stringstream stream(line);

        line_counter++;

        while (stream >> token)
        {
           bool found = false;
            for (auto& v : id_list)
            {
                if (v.id_name == token)
                {
                    //We have seen the word so add one to its count
                    v.id_ref++;
                    found = true;
                    break;
                }
            }
           if (token == "int" || token == "int*")
            {
                string star = token;
                identifier intI;

                stream >> token;
                string name = token;
               
                intI.id_name = name;
                intI.id_count = line_counter;
                intI.id_type = "int";
               
                stream >> token; //Get the next token
                if (token == "(")
                {
                    //We have a function
                    intI.id_function = "function";
                    
                    if (intI.id_name != "main")
                    {
                        intI.function_name = "(" + name + ")";
                    }
                    
                    num_functions++;
                }
                else
                {
                    //We have a variable
                    intI.id_function = "variable";

                    if (star == "int*")
                    {
                        intI.id_type = "int*";
                    }

                    num_variables++;
                }
                 id_list.push_back(intI);
            }
        }
    file.close();
    //Print the words and their counts
   
    for (auto& v : id_list)
    {
      cout << v.id_name << v.function_name << ", line " << v.id_count << ", " << v.id_function << ", " << v.id_type << ", referenced " << v.id_ref << endl;
    }

    return 0;
AxelCagira
  • 81
  • 6
  • I might just be blind, but I don't see `id_ref` being initialized anywhere. You also need to keep track of which function you're currently in, so as to be able to store it with the variables inside the function. – ChrisMM May 02 '21 at 11:14
  • I edited it, I forgot to add that bit of code, thanks for pointing it out. And, how can I do that? How can I store the function I am in? With a while loop that keeps it until it finds the token "}"? – AxelCagira May 02 '21 at 11:22

1 Answers1

1

I can see you're incrementing id_ref now, but it's still not initialized, so you have undefined behaviour. Easiest way is to do = 0; where its defined in the struct.

As for your function, assuming there's no nested functions here, then you can just use a variable to keep track of that.

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>

struct identifier {
    std::string id_name;
    std::string function_name;
    int id_count;
    std::string id_function;
    std::string id_type;
    int id_ref = 0; // if not initialized, then you will get seemingly random numbers

};

int main( int argc, char **argv ) {


    if ( argc < 2 )     {
        std::cout << "ERROR: There is no file selected." << std::endl;
        return 1; // quit early
    }

    std::ifstream file( argv[1] );
    std::string line;
    std::string token;
    std::vector<identifier> id_list;

    int line_counter = 0;
    int num_functions = 0;
    int num_variables = 0;
    int num_if = 0;
    int num_for = 0;
    int num_while = 0;

    std::string current_function; // keep track of the function


    while ( std::getline( file, line ) ) {
        std::stringstream stream( line );

        line_counter++;

        while ( stream >> token ) {
            bool found = false;
            for ( auto &v : id_list ) {
                if ( v.id_name == token ) {
                    //We have seen the word so add one to its count
                    v.id_ref++;
                    found = true;
                    break;
                }
            }
            if ( token == "int" || token == "int*" ) {
                std::string star = token;
                identifier intI;

                stream >> token;
                std::string name = token;

                intI.id_name = name;
                intI.id_count = line_counter;
                intI.id_type = "int";

                stream >> token; //Get the next token
                if ( token == "(" ) {
                    //We have a function
                    intI.id_function = "function";

                    if ( intI.id_name != "main" ) {
                        current_function = name; // update the current function name

                    }

                    num_functions++;
                } else {
                    intI.function_name = "(" + current_function + ")"; // add the function name to the variable name
                    //We have a variable
                    intI.id_function = "variable";

                    if ( star == "int*" ) {
                        intI.id_type = "int*";
                    }

                    num_variables++;
                }
                id_list.push_back( intI );
            }
        }
    }
    //file.close();
    //Print the words and their counts

    for ( const auto &v : id_list ) {
        std::cout << v.id_name << v.function_name << ", line " << v.id_count << ", " << v.id_function << ", " << v.id_type << ", referenced " << v.id_ref << std::endl;
    }

    return 0;
}

Also, some recommended reading on using namespace std

Working example modified to work with a string, instead of parameter: https://godbolt.org/z/jKqqrhce6

ChrisMM
  • 8,448
  • 13
  • 29
  • 48
  • Thanks a lot for the help, it works flawlessly! Plus all the reading recommendations and the compiler link. I'll check them out. – AxelCagira May 02 '21 at 12:40