Your first task is to implement parse_file, so that it reads a makefile and constructs a corresponding linked data structure. The necessary structs are defined in pmake.h, and the comments at the top of the file explain what each line of a makefile will contain. You may not change the struct definitions. pmake.h also contains function prototypes for functions that are either already provided, or that you will need to write.

The starter code also contains a makefile named handout.mk.  (This file and the required source and header files are in the subdirectory handout_example. ) The picture above shows a data structure that could result from parsing this file. Notice that there is one struct rule_node for each rule in the original makefile and an additional struct rule_node for each dependency that is not also a target. You must follow this design. You are are also required to have the head of the list be the first rule in the original makefile. However, depending on how you do your parsing, the struct rule_node elements may come in a different order in your linked list of rules.

Before reading any more of this handout, spend time to make sure you understand this figure and how it connects to the original makefile and the structs defined in pmake.h.

You will see that the actions are stored in a struct action_node that has a member args. This array has the format required by the second parameter to execvp. Use the man page for execvp to understand this format. In particular, notice that the first element is the executable name, subsequent elements are the arguments for that executable, and these are followed by an extra NULL pointer element.

The real make program supports a fairly complex syntax for writing makefiles. For the purposes of this assignment, your implementation of pmake only needs to support makefiles with the following simplified syntax.

A line from a makefile is either a target line, an action line, or a comment or line to ignore.

Target line
Starts with a target word, followed by a colon, followed by a space-separated list of dependencies.
The colon has space on each side of it.
Action line
Begins with a tab
After the tab is a command that can be executed in the shell.
Must follow a target line or another action line (possibly with comments/empty lines in between).
 Comment or empty line
Contains only spaces and/or tabs.
Or, contains 0 or more spaces/tabs followed by a #.  Any characters following the # are ignored.
You may make the following assumptions about the format and contents of the Makefile:

The Makefile syntax is valid (i.e., follows the structure described above).
Each target name, dependency name, and action word contains no spaces. This allows you to tokenize each line by splitting on spaces.
Every line in the file contains at most MAXLINE characters, where MAXLINE is a macro defined in pmake.h. This limit includes the newline character \n at the end of a line, if present. It does not include a null-terminator character.
Does not contain variables (e.g., $@), wild cards (e.g., %.o), pattern rules, .PHONY, or special characters at the start of an action line (e.g., @ or -).
The Makefile contains at least one rule.
The Makefile does not contain any circular dependencies (e.g., where target A depends on B, and target B depends on A).