tracesrv/tracecompiler/src/com.nokia.tracecompiler/src/com/nokia/tracecompiler/source/ExcludedAreaParser.java
changeset 56 aa2539c91954
parent 41 838cdffd57ce
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tracesrv/tracecompiler/src/com.nokia.tracecompiler/src/com/nokia/tracecompiler/source/ExcludedAreaParser.java	Fri Oct 08 14:56:39 2010 +0300
@@ -0,0 +1,352 @@
+/*
+* 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 comments and strings
+*
+*/
+package com.nokia.tracecompiler.source;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Parser for comments and strings
+ * 
+ */
+final class ExcludedAreaParser {
+
+	/**
+	 * The check range is used to limit the effect of unterminated ' in code
+	 */
+	private static final int CHAR_CHECK_RANGE = 3; // CodForChk_Dis_Magic
+
+	/**
+	 * Source parser
+	 */
+	private SourceParser parser;
+
+	/**
+	 * List of source file areas that are not used in search
+	 */
+	private ArrayList<SourceExcludedArea> excludedAreas = new ArrayList<SourceExcludedArea>();
+
+	/**
+	 * Comparator for array sorting and searching
+	 */
+	private PositionArrayComparator arrayComparator = new PositionArrayComparator();
+
+	/**
+	 * Constructor
+	 * 
+	 * @param parser
+	 *            the source parser
+	 */
+	ExcludedAreaParser(SourceParser parser) {
+		this.parser = parser;
+	}
+
+	/**
+	 * Resets the excluded areas
+	 */
+	void reset() {
+		excludedAreas.clear();
+	}
+
+	/**
+	 * Finds the array index of the excluded area which contains the offset. If
+	 * none of the areas contain the offset, returns negative integer indicating
+	 * the index of the excluded area following the offset
+	 * 
+	 * @param offset
+	 *            the offset to the data
+	 * @return the excluded area index
+	 */
+	int find(int offset) {
+		return Collections.binarySearch(excludedAreas, new SourceLocationBase(
+				parser, offset), arrayComparator);
+	}
+
+	/**
+	 * Finds the excluded source file areas. Excluded areas include comments and
+	 * quoted strings. Overwrites possible old areas.
+	 * 
+	 * @throws SourceParserException
+	 *             if processing fails
+	 */
+	void parseAll() throws SourceParserException {
+		excludedAreas.clear();
+		ExcludedAreaSearchData data = new ExcludedAreaSearchData();
+		int length = parser.getSource().getLength();
+		SourceExcludedArea lastarea = parse(data, length);
+		if (data.inString || data.inChar || data.inComment
+				|| data.inLineComment || data.inPreprocessor) {
+			lastarea.setLength(parser.getSource().getLength()
+					- lastarea.getOffset());
+			excludedAreas.add(lastarea);
+		}
+	}
+
+	/**
+	 * Parses the excluded areas of source
+	 * 
+	 * @param data
+	 *            the search data
+	 * @param length
+	 *            the length of data to be parsed
+	 * @return the last area
+	 * @throws SourceParserException
+	 *             if parser fails
+	 */
+	private SourceExcludedArea parse(ExcludedAreaSearchData data, int length)
+			throws SourceParserException {
+		SourceExcludedArea area = null;
+		while (data.index < length) {
+			data.value = parser.getSource().getChar(data.index++);
+			// Line comments end at end-of-line
+			if (data.inLineComment) {
+				processInLineComment(data, area);
+			} else if (data.inComment) {
+				processInComment(data, area);
+			} else if (data.inPreprocessor) {
+				processInPreprocessor(data, area);
+			} else if (data.inString) {
+				processInString(data, area);
+			} else if (data.inChar) {
+				processInChar(data, area);
+			} else if (data.value == '/' && data.index < length) {
+				area = createCommentArea(data);
+			} else if (data.value == '\"') {
+				area = createStringArea(data);
+			} else if (data.value == '\'') {
+				area = createCharArea(data);
+			} else if (data.value == '#'
+					&& (data.index == 1 || parser.getSource().getChar(
+							data.index - 2) == '\n')) { // CodForChk_Dis_Magic
+				area = createPreprocessorArea(data);
+			}
+		}
+		return area;
+	}
+
+	/**
+	 * Gets the excluded area that contains given offset
+	 * 
+	 * @param offset
+	 *            the offset to the area
+	 * @return the area or null if offset does not hit any area
+	 */
+	SourceExcludedArea getArea(int offset) {
+		SourceExcludedArea retval;
+		int index = find(offset);
+		if (index >= 0) {
+			retval = excludedAreas.get(index);
+		} else {
+			retval = null;
+		}
+		return retval;
+	}
+
+	/**
+	 * Gets the list of excluded areas
+	 * 
+	 * @return the list of areas
+	 */
+	List<SourceExcludedArea> getAreas() {
+		return excludedAreas;
+	}
+
+	/**
+	 * Processes a quote (') character marking start of character area
+	 * 
+	 * @param data
+	 *            the search flags
+	 * @return the new area
+	 */
+	private SourceExcludedArea createCharArea(ExcludedAreaSearchData data) {
+		SourceExcludedArea area;
+		data.inChar = true;
+		area = new SourceExcludedArea(parser, data.index - 1,
+				SourceExcludedArea.CHARACTER);
+		return area;
+	}
+
+	/**
+	 * Processes a double quote (") character marking start of string area
+	 * 
+	 * @param data
+	 *            the search flags
+	 * @return the new area
+	 */
+	private SourceExcludedArea createStringArea(ExcludedAreaSearchData data) {
+		SourceExcludedArea area;
+		data.inString = true;
+		area = new SourceExcludedArea(parser, data.index - 1,
+				SourceExcludedArea.STRING);
+		return area;
+	}
+
+	/**
+	 * Processes a forward slash (/) character marking start of comment
+	 * 
+	 * @param data
+	 *            the search flags
+	 * @return the comment object
+	 * @throws SourceParserException
+	 *             if processing fails
+	 */
+	private SourceExcludedArea createCommentArea(ExcludedAreaSearchData data)
+			throws SourceParserException {
+		SourceExcludedArea area;
+		char next = parser.getSource().getChar(data.index);
+		if (next == '/') {
+			data.inLineComment = true;
+			area = new SourceExcludedArea(parser, data.index - 1,
+					SourceExcludedArea.LINE_COMMENT);
+			data.index++;
+		} else if (next == '*') {
+			data.inComment = true;
+			area = new SourceExcludedArea(parser, data.index - 1,
+					SourceExcludedArea.MULTILINE_COMMENT);
+			data.index++;
+		} else {
+			area = null;
+		}
+		return area;
+	}
+
+	/**
+	 * Processes a preprocessor definition
+	 * 
+	 * @param data
+	 *            the search flags
+	 * @return the preprocessor area representation
+	 */
+	private SourceExcludedArea createPreprocessorArea(
+			ExcludedAreaSearchData data) {
+		SourceExcludedArea area = new SourceExcludedArea(parser,
+				data.index - 1, SourceExcludedArea.PREPROCESSOR_DEFINITION);
+		data.inPreprocessor = true;
+		return area;
+	}
+
+	/**
+	 * Processes a character that belongs to '' area
+	 * 
+	 * @param data
+	 *            the search flags
+	 * @param area
+	 *            the area under processing
+	 * @throws SourceParserException
+	 *             if processing fails
+	 */
+	private void processInChar(ExcludedAreaSearchData data,
+			SourceExcludedArea area) throws SourceParserException {
+		// The check range is used to limit the effect of unterminated '
+		if ((data.value == '\'' && parser.getSource().getChar(data.index - 2) != '\\') // CodForChk_Dis_Magic
+				|| data.index - area.getOffset() > CHAR_CHECK_RANGE) {
+			data.inChar = false;
+			area.setLength(data.index - area.getOffset());
+			excludedAreas.add(area);
+		}
+	}
+
+	/**
+	 * Processes a character that belongs to "" area
+	 * 
+	 * @param data
+	 *            the search flags
+	 * @param area
+	 *            the area under processing
+	 * @throws SourceParserException
+	 *             if processing fails
+	 */
+	private void processInString(ExcludedAreaSearchData data,
+			SourceExcludedArea area) throws SourceParserException {
+		// Strings end with " unless escaped with \" (except \\")
+		if (data.value == '\"') {
+			if (parser.getSource().getChar(data.index - 2) != '\\' // CodForChk_Dis_Magic
+					|| parser.getSource().getChar(data.index - 3) == '\\') { // CodForChk_Dis_Magic
+				data.inString = false;
+				area.setLength(data.index - area.getOffset());
+				excludedAreas.add(area);
+			}
+		}
+	}
+
+	/**
+	 * Processes a character that belongs to multi-line comment
+	 * 
+	 * @param data
+	 *            the search flags
+	 * @param area
+	 *            the area under processing
+	 * @throws SourceParserException
+	 *             if processing fails
+	 */
+	private void processInComment(ExcludedAreaSearchData data,
+			SourceExcludedArea area) throws SourceParserException {
+		// Comments end with */
+		if (data.value == '*') {
+			if (data.index < parser.getSource().getLength()
+					&& parser.getSource().getChar(data.index) == '/') {
+				data.index++;
+				data.inComment = false;
+				area.setLength(data.index - area.getOffset());
+				excludedAreas.add(area);
+			}
+		}
+	}
+
+	/**
+	 * Processes a character that belongs to line comment
+	 * 
+	 * @param data
+	 *            the search flags
+	 * @param area
+	 *            the area under processing
+	 */
+	private void processInLineComment(ExcludedAreaSearchData data,
+			SourceExcludedArea area) {
+		if (data.value == '\n') {
+			data.inLineComment = false;
+			area.setLength(data.index - area.getOffset());
+			excludedAreas.add(area);
+		}
+	}
+
+	/**
+	 * Processes a character that belongs to preprocessor definition
+	 * 
+	 * @param data
+	 *            the search flags
+	 * @param area
+	 *            the area under processing
+	 * @throws SourceParserException
+	 *             if processing fails
+	 */
+	private void processInPreprocessor(ExcludedAreaSearchData data,
+			SourceExcludedArea area) throws SourceParserException {
+		if (data.value == '\n') {
+			char prev = parser.getSource().getChar(data.index - 2); // CodForChk_Dis_Magic
+			char prev2 = parser.getSource().getChar(data.index - 3); // CodForChk_Dis_Magic
+			if (!((prev == '\\') || (prev == '\r' && prev2 == '\\'))) {
+				data.inPreprocessor = false;
+				area.setLength(data.index - area.getOffset());
+				excludedAreas.add(area);
+			}
+		}
+	}
+}