Project #3 Sample - Code Analyzer with Abstract Syntax Tree

Version 1.0,
Due Date: Already Completed - find code here
Note:
This is a demonstration project, which you are not expected to implement.
Instead, you will implement the projects linked on the Synchronous pages.

Purpose:

This project will build on the parser developed in Sample Project #2. Here, we add an Abstract Syntax Tree (AST) to the backend of our rule-based parser. You will find it useful to re-read the Parser Blog, before starting work on this project.
Parsing generates a lot of information that is transient unless we take some specific actions to capture it while processing source code. In this project we will store the static structure of analyzed code in a tree of scopes, e.g., the AST.
The root scope is the global namespace, above any namespace or class declaration, sometimes indicated by the scope resolution operator ::. Each time analysis encounters an open brace, '{', that defines a new scope which is a child of the scope prior to the brace. We leave that scope when we encounter a closed brace, '}'.
The AST is constructed by pushing a node, representing the global scope, onto a scope stack1. The next scope encountered is a child, so we link the top of the scope stack to the child and push the child onto the scope stack. This is a potentially recursive definition, resulting in a tree of scopes. For each encountered scope, we create a child scope, link to the scope at the top of the scope stack, and push onto the stack. When we encounter the end of a scope, we pop the top of scope stack, leaving the linkage from the parent. When we reach the end of the current source code file we will have a linked tree of scopes with only the root global namespace scope left on the scope stack2, 3.
When analysis of a source code file is complete, the AST is a tree containing all of the scopes in the same hierarchal order as encountered in the file. We will find the AST to be useful for creating analysis displays, and as the starting point for other analyses, e.g., type-based dependency analysis.
You are expected to support the analysis of all files matching a specified set of patterns, e.g., *.h and *.cpp, contained in the entire directory tree rooted at a specified path.

Requirements:

Your Parser with AST project:
  1. Shall be written in C++, using the standard C++ libraries. You may also use helper code provided in the course Repository.
  2. Shall use Visual Studio, Community Edition available at no cost.
  3. Shall be built as a Windows console application, and shall accept, on the command-line, a path to directory tree containing files to be analyzed, and sufficient options to support the processing described below.
  4. Shall provide, in addition to the packages used for Project #2, a package for a scope stack, and a package for an Abstract Syntax Tree.
  5. The ScopeStack package shall provide a class that implements stack functionality, but also supports accessing elements below the stack top. That access is needed while building the AST.
  6. The AbstractSynTree package shall provide facilities for building an AST, using a ScopeStack instance, as described in the purpose section.
  7. Shall provide a command-line option to display size and complexity of each function encountered during analysis. Complexity is the total number of scopes encountered in each function, including the function's scope.
  8. For member functions that are declared outside the class scope, perhaps in a separate file, shall relink those functions to their class, in the order declared in the class declaration, as if they were defined in-line.
  9. Shall provide the same display4 used in Project #2, followed by a display of the AST as an indented list of scopes with identifiers.

  1. A scope stack is an instance of a class with stack functionality, that also provides access to elements of the stack below the stack top.
  2. To help you understand this process, you may find it useful to construct a sequence of sketches each illustrating the stack and AST state for a simple program with just a few scopes.
  3. Scopes from subsequent files in the analysis sequence simply become siblings of the global namespace scope's children.
  4. You may improve the display you provided in Project #2 if that seems appropriate.

What you need to know:

In order to successfully meet these requirements you will need to know:
  1. The ideas discussed in the Parser Blog.
  2. Use of C++ pointers. You should consider using native, or std::unique_ptr, or std::shared_ptr.