diff -r a151135b0cf9 -r aa2539c91954 tracesrv/tracecompiler/src/com.nokia.tracecompiler/src/com/nokia/tracecompiler/source/ExcludedAreaParser.java --- /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 excludedAreas = new ArrayList(); + + /** + * 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 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); + } + } + } +}