CMPSC 311, Spring 2013, Project 5

Posted Feb. 25, 2013.  Due Mar. 13, 2013, by 11:55 pm on ANGEL.  25 points.

The goal of this project is to implement part of the make utility, as a continuation of Project 4.

You should create a project5 directory along the lines of Projects 2, 3 and 4.  Again, if you have any problems using Unix, the editors or the compilers, don't hesitate to ask for help.  Otherwise, do this project on your own.

(Added, Feb. 28, a small change to the example, changing $(macro-1} to ${macro-1})



Starting from Project 4, implement macro definition and macro expansion in the Hake program.  You can start from your own solution to Project 4, or from the posted solution on ANGEL.

Here is one way to design and test the macro code:
The functions in macro.c implement a simple macro definition and expansion library, with a separate test program.  Be sure to write some more rigorous tests.  Try to remove the assumption that the array used to hold an expanded line is actually large enough.  In general, try to make the macro.c functions resistent to failure.

The code doesn't need to take elaborate actions when given faulty input, as would come from
target : $SRC
target : ${SRC
target : $(SRC)
target : ${${SRC}}
It would be helpful to issue an error message in cases like these, but you don't need to try to "fix" the problems.   (The first two cases are just mistakes, the third case looks like macro usage in the Make program, and the fourth case is just suspicious.)



When your code is complete and you are satisfied it is right, here is how to turn it in for a grade.

Login to one of the CSE Linux or Solaris systems, cd to your cmpsc311/project5 directory, maybe transfer files from your home system, and run some final tests just to make sure.

Your code should be in one or more files named hake.c, cmpsc311.c, cmpsc311.h, names.c, names.h, macro.c and macro.h, which each start like
/* CMPSC 311, Spring 2013, Project 5
*
* Author: <your name>
* Email: <your preferred email address>
*
... <additional comment text>
*/
except, of course, your own name and address should be there.

You should have a file named Makefile, which could be the same as the one linked above.  Modify Makefile, to enter your own name and address.  Otherwise, just add to it, and don't remove any of the targets that are already there.

Pick up (i.e., download or copy) the file README, and modify it accordingly.  Any messages or comments about the project should go here.

Pick up the file wrap, and don't change it.  This contains the shell script that will bundle your project files.

Execute the command
sh wrap
which (if you have done everything right) should produce output like this.  If you made a mistake, you would get output like this instead.  You can expect some variation in the output because of different user names, file modification times, file sizes, Linux vs. Solaris, etc.

The wrap script will create a "gzipped tar file" containing the files README, Makefile, hake.c, etc., and some additional data.  The actual name of the file depends on your username.  Tar stands for "tape archive"; it accumulates a collection of files into one file, preserving ownership and date information.  gzip does file compression, and the original tar file will be recovered by using gunzip.

Login to ANGEL and put the file project-5-username.tar.gz in the ANGEL Dropbox for Project 5 (with your username substituted, of course).
The ANGEL Dropbox will be open for two days after the due date, but you really should get this in on time.  Nothing will be accepted more than two days late.

Only the most recent version in the Dropbox will be graded.



Additional Notes.
If you have questions about the assignment description or expectations, or need more examples, send mail to dheller at cse.psu.edu, with the subject line "CMPSC 311 Project 5" (this will help keep things organized).



Here is an example, on Linux.  The program prints each input line before and after macro expansion.

% make hake-gcc
gcc -std=c99 -D_XOPEN_SOURCE=700 -Wall -Wextra -o hake hake.c cmpsc311.c names.c macro.c

% cat Hakefile

# comment 1

macro-1 = body-1
macro-2 = body-2
macro-3 = ${macro-1} ${macro-2}

target1 : source1 source2
    recipe 1 ${macro-1}
    recipe 2 ${macro-2}
    recipe 3 ${macro-3}

include testfile-1

# comment 2


% cat testfile-1
# testfile-1

% hake -v
hake: read_file(hakefile)
list of names: filenames
  hakefile
hake: read_file(Hakefile)
list of names: filenames
  hakefile
  Hakefile
hake: read_lines(Hakefile)
hake: Hakefile: line 1: # comment 1
hake: Hakefile: line 1: # comment 1
hake: Hakefile: line 2:
hake: Hakefile: line 2:
hake: Hakefile: line 3: macro-1 = body-1
hake: Hakefile: line 3: macro-1 = body-1
  diagnosis: macro definition
hake: Hakefile: line 4: macro-2 = body-2
hake: Hakefile: line 4: macro-2 = body-2
  diagnosis: macro definition
hake: Hakefile: line 5: macro-3 = ${macro-1} ${macro-2}
hake: Hakefile: line 5: macro-3 = body-1 body-2
  diagnosis: macro definition
hake: Hakefile: line 6:
hake: Hakefile: line 6:
hake: Hakefile: line 7: target1 : source1 source2
hake: Hakefile: line 7: target1 : source1 source2
  diagnosis: target-prerequisite
hake: Hakefile: line 8:     recipe 1 ${macro-1}
hake: Hakefile: line 8:     recipe 1 body-1
  diagnosis: recipe line 1
hake: Hakefile: line 9:     recipe 2 ${macro-2}
hake: Hakefile: line 9:     recipe 2 body-2
  diagnosis: recipe line 2
hake: Hakefile: line 10:     recipe 3 ${macro-3}
hake: Hakefile: line 10:     recipe 3 body-1 body-2
  diagnosis: recipe line 3
hake: Hakefile: line 11:
hake: Hakefile: line 11:
hake: Hakefile: line 12: include testfile-1
hake: Hakefile: line 12: include testfile-1
  diagnosis: include
hake: read_file(testfile-1)
list of names: filenames
  hakefile
  Hakefile
  testfile-1
hake: read_lines(testfile-1)
hake: testfile-1: line 1: # testfile-1
hake: testfile-1: line 1: # testfile-1
hake: Hakefile: line 13:
hake: Hakefile: line 13:
hake: Hakefile: line 14: # comment 2
hake: Hakefile: line 14: # comment 2


Here is the test program.

% gcc -std=c99 -D_XOPEN_SOURCE=700 -Wall -Wextra macro_test.c cmpsc311.c macro.c

% a.out
Macro list
  -- end of list
Macro list
  C = ccc (3)
  B = bb (2)
  A = a (1)
  -- end of list
Macro list
  C = ccc (3)
  B = dddd (4)
  A = a (1)
  -- end of list
Macro list
  C = ccc (3)
  B = dddd (4)
  A = eeeee (5)
  -- end of list
A = 'eeeee' (5)
B = 'dddd' (4)
C = 'ccc' (3)
D = '' (0)
len 21
25 test.${A}.${B}.${C}.${D}.
21 test.eeeee.dddd.ccc..
len 21
Macro list
  C = ccc (3)
  B = dddd (4)
  A = ${B} (4)
  -- end of list
len 20
25 test.${A}.${B}.${C}.${D}.
20 test.${B}.dddd.ccc..
len 20
Macro list
  D = enough already! (15)
  C = body body body (14)
  B = body body (9)
  A = body (4)
  -- end of list
len 51
25 test.${A}.${B}.${C}.${D}.
51 test.body.body body.body body body.enough already!.
len 51





Last modified, 28 Feb. 2013