LibstdioASTTransformer.java

package edu.udel.cis.vsl.tass.library.libstdio;

import java.util.ArrayList;

import edu.udel.cis.vsl.tass.ast.IF.ASTFactoryIF;
import edu.udel.cis.vsl.tass.ast.IF.ASTTransformerIF;
import edu.udel.cis.vsl.tass.ast.IF.AbstractSyntaxTreeIF;
import edu.udel.cis.vsl.tass.ast.IF.GlobalScopeNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.IdentifierNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.SequenceNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.TypeDefinitionNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.type.CompositeTypeNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.type.TypeNodeIF;
import edu.udel.cis.vsl.tass.model.IF.SyntaxException;
import edu.udel.cis.vsl.tass.util.Pair;
import edu.udel.cis.vsl.tass.util.TASSInternalException;

/**
 * Adds types to the AST: STDIO_File and STDIO_Stream. A skeleton definition of
 * STDIO_Stream should already be present (from parsing stdio.h), but will have
 * to be modified.
 * 
 * More precisely, the AST is expected to have a global scope node N of the form
 * "typedef ... FILE". This will (1) insert the typedef of STDIO_File given
 * below as a global scope node just before N, and (2) replace the "..." in N
 * with the definition of "struct STDIO_Stream" given below.
 * 
 * <code>
 * typedef struct STDIO_File {
 *   char filename[];    // the name of the file (including path)
 *   boolean isOutput;   // is this an output file? 
 *   boolean isInput;    // is this an input file? 
 *   boolean isBinary;   // can be binary or text 
 *   boolean isWide;     // wide orientation 
 *   char[][] contents;  // file contents: ragged array 
 * } STDIO_File;
 * 
 * typedef struct STDIO_Stream {
 *   STDIO_File *file; // file to which this stream refers
 *   boolean isOpen;   // is this stream open?
 *   int position1;    // current word in file
 *   int position2;    // character index in word
 *   int mode;         // Stream mode: r/w/a
 * } FILE;
 * </code>
 * 
 * @author siegel
 * 
 */
public class LibstdioASTTransformer implements ASTTransformerIF {

	private ASTFactoryIF astFactory;

	public LibstdioASTTransformer(ASTFactoryIF astFactory) {
		this.astFactory = astFactory;
	}

	public ASTFactoryIF astFactory() {
		return astFactory;
	}

	@Override
	public String name() {
		return "libstdio";
	}

	private void add(ArrayList<Pair<String, TypeNodeIF>> fields,
			String fieldName, TypeNodeIF typeNode) {
		fields.add(new Pair<String, TypeNodeIF>(fieldName, typeNode));
	}

	/**
	 * Finds the global scope node child which is typedef FILE, inserts a global
	 * scope node before it, defining new type modify the FILE type definition.
	 */
	@Override
	public void transform(AbstractSyntaxTreeIF ast) throws SyntaxException {
		SequenceNodeIF<GlobalScopeNodeIF> root = ast.rootNode()
				.globalScopeNodes();

		int numChildren = root.numChildren();
		int fileTypeIndex = -1;
		ArrayList<Pair<String, TypeNodeIF>> fileFields = new ArrayList<Pair<String, TypeNodeIF>>(), streamFields = new ArrayList<Pair<String, TypeNodeIF>>();
		CompositeTypeNodeIF fileTypeNode, streamTypeNode;
		TypeDefinitionNodeIF fileTypedefNode, streamTypedefNode = null;

		for (int i = 0; i < numChildren; i++) {
			GlobalScopeNodeIF child = root.getSequenceChild(i);

			if (child instanceof TypeDefinitionNodeIF) {
				TypeDefinitionNodeIF typeDef = (TypeDefinitionNodeIF) child;
				IdentifierNodeIF identifier = typeDef.identifier();
				String typeName = identifier.name();

				if ("FILE".equals(typeName)) {
					fileTypeIndex = i;
					streamTypedefNode = (TypeDefinitionNodeIF) child;
					break;
				}
			}
		}
		if (streamTypedefNode == null)
			throw new TASSInternalException(
					"stdlib AST transformer unable to find FILE typedef");
		add(fileFields, "filename", astFactory.arrayTypeNode(astFactory
				.characterTypeNode()));
		add(fileFields, "isOutput", astFactory.booleanTypeNode());
		add(fileFields, "isInput", astFactory.booleanTypeNode());
		add(fileFields, "isBinary", astFactory.booleanTypeNode());
		add(fileFields, "isWide", astFactory.booleanTypeNode());
		add(fileFields, "contents", astFactory.arrayTypeNode(astFactory
				.arrayTypeNode(astFactory.characterTypeNode())));
		fileTypeNode = astFactory.compositeTypeNode("STDIO_File", fileFields,
				false);
		fileTypedefNode = astFactory.typeDefinitionNode(astFactory
				.identifierNode("STDIO_File"), fileTypeNode);
		root.insertChild(fileTypeIndex, fileTypedefNode);
		add(streamFields, "file", astFactory.pointerTypeNode(astFactory
				.typeReferenceNode(fileTypedefNode)));
		add(streamFields, "isOpen", astFactory.booleanTypeNode());
		add(streamFields, "position1", astFactory.integerTypeNode());
		add(streamFields, "position2", astFactory.integerTypeNode());
		add(streamFields, "mode", astFactory.integerTypeNode());
		streamTypeNode = astFactory.compositeTypeNode("STDIO_Stream",
				streamFields, false);
		streamTypedefNode.setType(streamTypeNode);
	}
}