Introduction | Projects and Files | Statements | Expressions | Symbols | Types |
Attributes | Labels | Non-Member Functions | Constructing Declarations | Example Programs | Index |
A project is a group of parsed source files
(.dep
files)
making up a program that is to be manipulated by Sage++. Currently,
Sage++ can only deal with one project at a time. If multiple files in
a project are desired, please see section Attributes.
On disk, a project is represented
as a file with name ending in .proj
, containing a list of names of the
component .dep
files, one file name per line.
A file is one of the parsed source files in a project.
Each .dep
file contains a parse tree. The root of the tree for
a file is called the global node and its immediate children are the
top level definitions and functions in the files. The file also
contains a symbol table and type table.
Refer to the Overview for more details about
.dep
files.
Represents the files in the current project, for all languages.
class SgProject { public: inline SgProject(SgProject &); SgProject(char * proj_file_name); inline ~SgProject(); inline int numberOfFiles(); SgFile &file(int i); inline char *fileName(int i); inline int Fortranlanguage(); inline int Clanguage(); void addFile(char * dep_file_name); void deleteFile(SgFile * file); };
SgProject
(char * proj_file_name)
SgProject
with this
constructor. The variable proj_file_name
is a string containing
the name of the .proj
file that corresponds to the program to be
manipulated.i
th file in the project.
i
th file in the project.
void addFile
(char * dep_file_name)
void deleteFile
(SgFile * file)
Typical usage of SgProject
is as in the following example:
#include "sage++user.h" main() { SgProject P("myproject.proj"); // opens and initializes project for(int i = 0; i < P.numberOfFiles(); i++){ printf(" file is %s\n", P.fileName(i)"); DoSomethingTo(P.file(i)); }; }
Here's another one:
#include <stdio.h> #include <GetOpt.h> #include "sage++user.h"int main (int argc, char **argv) { GetOpt getopt (argc, argv, "i:o:"); SgProject *project; int option_char; char *ifile, *ofile; while ((option_char = getopt ()) != EOF) switch (option_char) { case 'i': ifile = getopt.optarg; break; case 'o': ofile = getopt.optarg; break; case '?': fprintf (stderr, "usage: %s [i<input-proj> o<unparsed-file>]\n", argv[0]); } project = new SgProject (ifile);
/* do something with the project */ }
SgProject
is used in the following example programs:
This class provides access to the local symbol and type tables,
and the top level definitions, in the .dep
file it corresponds
to.
class SgFile { public: PTR_FILE filept; SgFile(char* file_name); // the file must exist. SgFile(int Language, char* file_name); // for new empty file objects. inline ~SgFile(); inline SgFile(SgFile &); inline int languageType(); inline void saveDepFile(char *dep_file); inline void unparse(FILE *filedisc); inline void unparsestdout();inline SgStatement *mainProgram(); SgStatement *functions(int i); inline int numberOfFunctions(); SgStatement *getStruct(int i); inline int numberOfStructs();
inline SgStatement *firstStatement(); inline SgSymbol *firstSymbol(); inline SgType *firstType(); inline SgExpression *firstExpression();
inline SgExpression *SgExpressionWithId(int i); inline SgStatement *SgStatementWithId( int id); inline SgStatement *SgStatementAtLine(int lineno); inline SgSymbol *SgSymbolWithId( int id); inline SgType *SgTypeWithId( int id); // for attributes; void saveAttributes(char *file); void saveAttributes(char *file, void (*savefunction)(void *dat,FILE *f)); void readAttributes(char *file); void readAttributes(char *file, void * (*readfunction)(FILE *f)); int numberOfAttributes(); SgAttribute *attribute(int i); int SgFile::expressionGarbageCollection(int deleteExpressionNode, int verbose); };
SgFile
(int Language, char* file_name)
.dep
file in order to insert statements into it later on. Please
see section SgFile Usage for a detailed description of this constructor.
CSrc
(for C) or ForSrc
(for Fortran).
void saveDepFile
(char *dep_file)
.dep
file
with filename dep_file
.
filedisc
.
NULL
if the main program is not located
in this file.
i
th function in the file.
i
th structure (? or class or union?)
in the file.
SgExpression *firstExpression
()
SgExpression *SgExpressionWithId
(int i)
i
.
SgStatement *SgStatementWithId
( int id)
id
.
SgStatement *SgStatementAtLine
(int lineno)
i
in the file.
SgSymbol *SgSymbolWithId
(int id)
id
.
id
.
Usually, the .dep
file is created by a parser and a Sage
program modifies an already existing .dep
file.
However, in some situations, there is a need for creating an empty
.dep
file and then adding statements to it.
In Sage++ version 1.7, a new constructor:
SgFile::SgFile(int Language, char * dep_file_name)
has been added. It can be used to create new, empty .dep
files.
The code fragment below shows an example of usage:
SgProject project("x.proj"); SgFile file(CSrc, "y.c"); // create a new file SgStatement *s = f->firstStatement(); SgPointerType *p, *q; SgType *v; if(s == NULL) printf("no first statement\n"); SgFuncHedrStmt *mane = new SgFuncHedrStmt("main"); mane->AddArg("argc",*SgTypeInt()); // add int argc v = new SgPointerType(*SgTypeChar()); q = new SgPointerType(*v); // note: new SgPointerType (*p) will not work, // the reason is that the default copy constructor is called mane->AddArg("argv", *q); // char ** argv s->insertStmtAfter(*mane);
Note that the "empty" file created by the SgFile constructor is not
really completely empty: it contains one statement (the global node).
Also, in order for the above example to work, you need to have
x.proj
and x.dep
files in the same directory.
Normally, you wouldn't instantiate a SgFile yourself. Rather, you
would instantiate a project, and then access the files in the project
through the file()
member of SgProject.
There are two ways to traverse a file. One way is to access each
subroutine and function by means of the numberOfFunctions()
and
functions(i)
methods.
For example, to print the names of all the subroutines
in the project, you might try:
SgProject *project; ... /* from Sage++ demo 'instrument', in function InitFunctionTable()) */for (int i = 0; i < project->numberOfFiles(); i++) { SgFile *f;
f = &(project->file(i)); int num_routines; num_routines = f->numberOfFunctions(); for (int j = 0; j < num_routines; j++){ SgStatement *sub; SgSymbol *subsym;
sub = f->functions(j); subsym = sub->symbol();
printf("Function %d's name is %s\n", i*Files+j, subsym->identifier()); } }
The other way to traverse a file is to access it in lexical order
starting with firstStatement()
, as in:
void traverseFile(SgFile *f) { SgStatement *s;for (s = f->firstStatement(); s; s = s->lexNext()) { /* Do something to the statement */ } }
SgFile
is used in the following example programs:
Multiple files capabilities exist in Sage, but there exists a set of limitations: only one file can be selected at a time. A file is selected by the methods:
SgProject::file(int i) SgFile::SgFile(char * dep_file_name)
When a file is selected, then all the operation in the data base will use the current file data structure (see Figure 1). For instance, if a statement is created, it is added in the current file structure. When the project is opened, then the first file is automatically selected.
Here is an example of the usage of the multiple file capability:
project = new SgProject("test.proj"); nbfile = project->numberOfFiles(); for (i=0; i< nbfile; i++) { file = &(project->file(i)); printf("|||||||||||||||||||||||||||||||||||||||||||||||||||||||||\n"); // any operations here will operate on file number i // file i has been selected by the method project->file(i)// do work here.......
file->unparsestdout(); }
Here is an example of code to retrieve a function code in a multiple file project:
nbfile = project->numberOfFiles(); printf("Give the name of the function: "); scanf("%s",str); for (i=0; i< nbfile; i++) { file = &(project->file(i)); if (!file) { Message("file not found",0); exit(1); } nbfunc = file->numberOfFunctions(); for (j=0; jfunctions(j); if (!strcmp(func->symbol()->identifier(),str)) { printf("Function %s found in file %s\n", func->symbol()->identifier(), project->fileName(i)); break; } } }
Copy across files must be done by the member function,
inline SgSymbol &SgSymbol::copyAcrossFiles(SgStatement &where)where the parameter
where
indicates where the statements will
be inserted. This method can only copy a full function, subroutine,
class or structure. It duplicates all the expressions, symbols and types
referenced in the body of a function, so that after the copy
there are no more references to the original file.
To illustrate the problem of copying across files, let's consider this incorrect example. The result is illustrated in Figure 2:
project = new SgProject("test.proj"); nbfile = project->numberOfFiles(); file = &(project->file(0)); func = file->functions(0); // take the first function of file 0 to // be copied and inserted in the other file func->extractStmt(); // extract to allow copy for (i=1; i< nbfile; i++) { file = &(project->file(i)); if (!file) { Message("file not found",0); exit(1); } first = file->firstStatement(); copyoffunc = &(func->copy()); // THIS IS REALLY WRONG first->insertStmtAfter(*copyoffunc); printf("|||||||||||||||||||||||||||||||||||||||||||||||||||||||||\n"); file->unparsestdout(); // unparse correctly but database is corrupted. sprintf(str,"debug%d.dep",i); file->saveDepFile(str); // incorrect database output. }
Remark: Even though the multiple file operation is very limited and fragile it is still possible to use it for creating complex data structures easily. In one file an object to be copied can be created by the parser. It can then be copied into another file to be used as a template.
..... project = new SgProject("test.proj"); nbfile = project->numberOfFiles(); // set to the first file file = &(project->file(0)); // get the first function func = file->functions(0); // get the symbol fc = func->symbol(); // the following loop add the first function // of file number 0 to all the other files for (i=1; i< nbfile; i++) { file = &(project->file(i)); first = file->firstStatement(); // call the copy across file function fccop = &(fc->copyAcrossFiles(*first)); // how to get the corresponding statement copyoffunc = fccop->body(); file->unparsestdout(); } ..... }