trace/tracebuilder/com.nokia.tracebuilder/src/com/nokia/tracebuilder/source/PreprocessorDefinitionParser.java
author Matti Laitinen <matti.t.laitinen@nokia.com>
Wed, 23 Jun 2010 14:35:40 +0300
changeset 10 ed1c9f64298a
permissions -rw-r--r--
TraceBuilder 2.4.0

/*
* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
* Parser for preprocessor definitions and include statements
*
*/
package com.nokia.tracebuilder.source;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * Parser for preprocessor definitions and include statements
 * 
 */
class PreprocessorDefinitionParser {

	/**
	 * Source parser
	 */
	private SourceParser parser;

	/**
	 * List of #define's found from source
	 */
	protected ArrayList<SourcePreprocessorDefinition> preprocessorDefinitions;

	/**
	 * List of #include's found from source
	 */
	protected ArrayList<SourceInclude> includes;

	/**
	 * Constructor
	 * 
	 * @param parser
	 *            the source parser
	 */
	PreprocessorDefinitionParser(SourceParser parser) {
		this.parser = parser;
	}

	/**
	 * Resets all definitions parsed from the source
	 */
	void reset() {
		if (preprocessorDefinitions != null) {
			preprocessorDefinitions.clear();
		}
		if (includes != null) {
			includes.clear();
		}
	}

	/**
	 * Locates the value of a preprocessor definition for given name.
	 * 
	 * @param name
	 *            the name of the definition
	 * @return the value or null if not found
	 * @throws SourceParserException
	 *             if parser fails
	 */
	String findDefine(String name) throws SourceParserException {
		if (preprocessorDefinitions == null
				|| preprocessorDefinitions.isEmpty()) {
			createDefines();
		}
		Iterator<SourcePreprocessorDefinition> itr = preprocessorDefinitions
				.iterator();
		String retval = null;
		while (itr.hasNext() && retval == null) {
			SourcePreprocessorDefinition def = itr.next();
			if (def.getName().equals(name)) {
				retval = def.getValue();
			}
		}
		return retval;
	}

	/**
	 * Finds an include definition with given name
	 * 
	 * @param name
	 *            the include file name
	 * @return
	 *            <ul>
	 *            <li>if found, index to start of #include
	 *            <li>if not, -1 - index to end of last #include
	 *            </ul>
	 * @throws SourceParserException
	 *             if parser fails
	 */
	int findInclude(String name) throws SourceParserException {

		createIncludes();

		Iterator<SourceInclude> itr = includes.iterator();
		int ret = -1;
		while (itr.hasNext()) {
			SourceInclude inc = itr.next();
			if (inc.getHeaderName().equalsIgnoreCase(name)) {
				ret = inc.getOffset();
			}
		}
		if (ret == -1 && includes.size() > 0) {
			SourceInclude inc = includes.get(includes.size() - 1);
			ret = -1 - (inc.getOffset() + inc.getLength());
		}
		return ret;
	}

	/**
	 * Creates the list of preprocessor definitions. This only works with simple
	 * values
	 * 
	 * @throws SourceParserException
	 *             if parser fails
	 */
	private void createDefines() throws SourceParserException {
		if (preprocessorDefinitions == null) {
			preprocessorDefinitions = new ArrayList<SourcePreprocessorDefinition>();
		} else {
			preprocessorDefinitions.clear();
		}
		Iterator<SourceExcludedArea> excludedAreas = parser.getExcludedAreas()
				.iterator();
		while (excludedAreas.hasNext()) {
			createDefineFromExcludedArea(excludedAreas.next());
		}
	}

	/**
	 * Creates the list of include definitions
	 * 
	 * @throws SourceParserException
	 *             if parser fails
	 */
	private void createIncludes() throws SourceParserException {
		if (includes == null) {
			includes = new ArrayList<SourceInclude>();
		} else {
			includes.clear();
		}
		Iterator<SourceExcludedArea> excludedAreas = parser.getExcludedAreas()
				.iterator();
		while (excludedAreas.hasNext()) {
			createIncludeFromExcludedArea(excludedAreas.next());
		}
	}

	/**
	 * Creates an #define definition from given excluded area
	 * 
	 * @param area
	 *            the area
	 * @throws SourceParserException
	 */
	private void createDefineFromExcludedArea(SourceExcludedArea area)
			throws SourceParserException {
		if (area.getType() == SourceExcludedArea.PREPROCESSOR_DEFINITION
				&& area.getLength() > SourceConstants.DEFINE.length()) {
			String tag = parser.getSource().get(area.getOffset(),
					SourceConstants.DEFINE.length());
			if (tag.equals(SourceConstants.DEFINE)) {
				// Cannot use SKIP_ALL here, since it contains SKIP_PREPROCESSOR
				SourceIterator itr = parser.createIterator(area.getOffset()
						+ SourceConstants.DEFINE.length(),
						SourceParser.SKIP_WHITE_SPACES
								| SourceParser.SKIP_COMMENTS);
				if (itr.hasNext()) {
					parsePreprocessorDefinition(itr);
				}
			}
		}
	}

	/**
	 * Creates an #include definition from given excluded area
	 * 
	 * @param area
	 *            the area
	 * @throws SourceParserException
	 *             if parser fails
	 */
	private void createIncludeFromExcludedArea(SourceExcludedArea area)
			throws SourceParserException {
		if (area.getType() == SourceExcludedArea.PREPROCESSOR_DEFINITION
				&& area.getLength() > SourceConstants.INCLUDE.length()) {
			String tag = parser.getSource().get(area.getOffset(),
					SourceConstants.INCLUDE.length());
			if (tag.equals(SourceConstants.INCLUDE)) {
				// Cannot use SKIP_ALL here, since it contains SKIP_PREPROCESSOR
				SourceIterator itr = parser.createIterator(area.getOffset()
						+ SourceConstants.INCLUDE.length(),
						SourceParser.SKIP_WHITE_SPACES
								| SourceParser.SKIP_COMMENTS);
				if (itr.hasNext()) {
					parseInclude(itr);
				}
			}
		}
	}

	/**
	 * Parses a preprocessor definition. This only finds simple values
	 * 
	 * @param itr
	 *            source iterator, positioned so that next will return the first
	 *            character of the name of the definition
	 * @throws SourceParserException
	 *             if parser fails
	 */
	private void parsePreprocessorDefinition(SourceIterator itr)
			throws SourceParserException {
		int start = itr.nextIndex();
		int defstart = -1;
		SourcePreprocessorDefinition def = new SourcePreprocessorDefinition(
				parser, start);
		while (itr.hasNext() && def != null) {
			itr.next();
			if (itr.hasSkipped()) {
				if (defstart == -1) {
					if ((itr.previousIndex() + 1) > start) {
						def.setName(parser.getSource().get(start,
								itr.previousIndex() + 1 - start));
						defstart = itr.currentIndex();
					} else {
						def = null;
					}
				} else {
					def.setValue(parser.getSource().get(defstart,
							itr.previousIndex() + 1 - defstart));
					def.setLength(itr.previousIndex() + 1 - def.getOffset());
					preprocessorDefinitions.add(def);
					def = null;
				}
			}
		}
	}

	/**
	 * Parses an include line
	 * 
	 * @param itr
	 *            source iterator, positioned so that next will return the first
	 *            character of the name of the definition
	 * @throws SourceParserException
	 *             if parser fails
	 */
	private void parseInclude(SourceIterator itr) throws SourceParserException {
		int start = itr.nextIndex();
		SourceInclude inc = new SourceInclude(parser, start);
		while (itr.hasNext() && inc != null) {
			itr.next();
			if (itr.hasSkipped() && (itr.previousIndex()) > (start + 1)) {
				inc.setHeaderName(parser.getSource().get(start + 1,
						itr.previousIndex() - (start + 1)));
				inc.setLength(itr.previousIndex() - inc.getOffset() + 1);
				includes.add(inc);
				inc = null;
			}
		}
	}

}