Entity vs. Reference

Now that we know how to start a python script to access the API and open an Understand project, we can look at the actual data from that project. Most of the data captured by Understand involves Entities and References.


Entity: An Entity is anything in the code that Understand captures information on: i.e. A file, a class, a variable, a function, etc. In the Python API Entities are represented with the Understand.Ent class.


Reference: A specific place where an entity appears in the code. A reference is always defined as a relationship between two entities. For example, function Bar is called on line 14 of function Foo. In the Python API References are represented with the Understand.Ref class.


Every entity and reference has a unique set of attributes that can be queried by the API. A few of the attributes you can view for an entity would be its name, its type, any associated comments, what kind of entity it is and its parent entity and parameters.


On the other hand, a reference would have both of the entities associated with it as well as the file, line, and column where the reference occurs and what kind of reference it is.


To help visualize this, let’s use this simple C code:


myFile.c


void main() {
   char myString[];
   myString = “Hello World!”;
}
C

Understand would identify three entities (blue) and three references (green):



Since all references are relationships between two objects, the references are actually stored going both directions. So each reference kind has an opposite: Define and DefineIn, Set and SetBy, Call and Callby, etc. Here are the same entities with their reverse references.



To get a list of all of the entities in the project, use the command db.ents(). To get a list of all of the references for an entity use ent.refs().


Usually we don’t want all of the entities or references, just some of them, and that is where kind filters come in.



Kind Filters


A Kind Filter is simply a string used to filter a list in Understand. We’ve already seen a small example in the first script we wrote:

db.ents("file"):
Perl

As noted earlier, the db.ents() command by itself returns a list of all of the entities in Understand, from loop variables to namespaces and everything in between. Specifying the “file” kind string creates a filter, everything that doesn’t match the filter is rejected. Only files are returned in this case.


You can add simple logic to the string as well:


tilde (~) means NOT

a space means AND

comma(,) can act as a top level OR


In our example if we wanted all classes and functions listed instead of files, we would just change the filter:

db.ents("class, function")
Perl

Which reads as: return any entity that is a class OR that is a function.


An unresolved entity is one that Understand has the declaration for, but not the definition (printf is a common example). This filter would return all non-volatile public functions that are defined in the project.

db.ents("function public ~unresolved ~volatile")
Perl



An Example


List the file and line where each function in the project is defined. This example assumes the Understand database has been opened already (see the templates at the end of the first tutorial).


First get a list of all functions defined in the project:

ents = db.ents("function ~unknown ~unresolved")
Perl


Then sort the list and iterate through it:

for ent in sorted(ents,key= lambda ent: ent.longname()):
Perl


Next, get the reference where each function is defined. If it doesn’t have a definition, skip to the next function:

ref = ent.ref("definein")
if ref is None:
    continue
Perl


Next, print the name of the function and it’s parameters:

print (ent.longname(),"(",ent.parameters(),")")
Perl


And finally print the file and line number where the reference occurs:

print (" ",ref.file().relname(),"(",ref.line(),")")
Perl
Perl

The entire script would look like this:

import understand db = understand.open("C:/projects/test.und")
ents = db.ents("function ~unknown ~unresolved")
for ent in sorted(ents,key= lambda ent: ent.longname()):
    ref = ent.ref("definein")
    if ref is None:
        continue
    print (ent.longname(),"(",ent.parameters(),")")
    print (" ",ref.file().relname(),"(",ref.line(),")")
Python



Continue to API Tutorial 4: Lexers and Lexemes ->


<- Return to API Tutorial 2: Writing Your First API Script



Need help? Contact [email protected] or visit our About the Understand Python API page.