tracesrv/tracecompiler/src/com.nokia.tracecompiler/src/com/nokia/tracecompiler/source/ExcludedAreaParser.java
changeset 56 aa2539c91954
parent 41 838cdffd57ce
equal deleted inserted replaced
54:a151135b0cf9 56:aa2539c91954
       
     1 /*
       
     2 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 * Parser for comments and strings
       
    17 *
       
    18 */
       
    19 package com.nokia.tracecompiler.source;
       
    20 
       
    21 import java.util.ArrayList;
       
    22 import java.util.Collections;
       
    23 import java.util.List;
       
    24 
       
    25 /**
       
    26  * Parser for comments and strings
       
    27  * 
       
    28  */
       
    29 final class ExcludedAreaParser {
       
    30 
       
    31 	/**
       
    32 	 * The check range is used to limit the effect of unterminated ' in code
       
    33 	 */
       
    34 	private static final int CHAR_CHECK_RANGE = 3; // CodForChk_Dis_Magic
       
    35 
       
    36 	/**
       
    37 	 * Source parser
       
    38 	 */
       
    39 	private SourceParser parser;
       
    40 
       
    41 	/**
       
    42 	 * List of source file areas that are not used in search
       
    43 	 */
       
    44 	private ArrayList<SourceExcludedArea> excludedAreas = new ArrayList<SourceExcludedArea>();
       
    45 
       
    46 	/**
       
    47 	 * Comparator for array sorting and searching
       
    48 	 */
       
    49 	private PositionArrayComparator arrayComparator = new PositionArrayComparator();
       
    50 
       
    51 	/**
       
    52 	 * Constructor
       
    53 	 * 
       
    54 	 * @param parser
       
    55 	 *            the source parser
       
    56 	 */
       
    57 	ExcludedAreaParser(SourceParser parser) {
       
    58 		this.parser = parser;
       
    59 	}
       
    60 
       
    61 	/**
       
    62 	 * Resets the excluded areas
       
    63 	 */
       
    64 	void reset() {
       
    65 		excludedAreas.clear();
       
    66 	}
       
    67 
       
    68 	/**
       
    69 	 * Finds the array index of the excluded area which contains the offset. If
       
    70 	 * none of the areas contain the offset, returns negative integer indicating
       
    71 	 * the index of the excluded area following the offset
       
    72 	 * 
       
    73 	 * @param offset
       
    74 	 *            the offset to the data
       
    75 	 * @return the excluded area index
       
    76 	 */
       
    77 	int find(int offset) {
       
    78 		return Collections.binarySearch(excludedAreas, new SourceLocationBase(
       
    79 				parser, offset), arrayComparator);
       
    80 	}
       
    81 
       
    82 	/**
       
    83 	 * Finds the excluded source file areas. Excluded areas include comments and
       
    84 	 * quoted strings. Overwrites possible old areas.
       
    85 	 * 
       
    86 	 * @throws SourceParserException
       
    87 	 *             if processing fails
       
    88 	 */
       
    89 	void parseAll() throws SourceParserException {
       
    90 		excludedAreas.clear();
       
    91 		ExcludedAreaSearchData data = new ExcludedAreaSearchData();
       
    92 		int length = parser.getSource().getLength();
       
    93 		SourceExcludedArea lastarea = parse(data, length);
       
    94 		if (data.inString || data.inChar || data.inComment
       
    95 				|| data.inLineComment || data.inPreprocessor) {
       
    96 			lastarea.setLength(parser.getSource().getLength()
       
    97 					- lastarea.getOffset());
       
    98 			excludedAreas.add(lastarea);
       
    99 		}
       
   100 	}
       
   101 
       
   102 	/**
       
   103 	 * Parses the excluded areas of source
       
   104 	 * 
       
   105 	 * @param data
       
   106 	 *            the search data
       
   107 	 * @param length
       
   108 	 *            the length of data to be parsed
       
   109 	 * @return the last area
       
   110 	 * @throws SourceParserException
       
   111 	 *             if parser fails
       
   112 	 */
       
   113 	private SourceExcludedArea parse(ExcludedAreaSearchData data, int length)
       
   114 			throws SourceParserException {
       
   115 		SourceExcludedArea area = null;
       
   116 		while (data.index < length) {
       
   117 			data.value = parser.getSource().getChar(data.index++);
       
   118 			// Line comments end at end-of-line
       
   119 			if (data.inLineComment) {
       
   120 				processInLineComment(data, area);
       
   121 			} else if (data.inComment) {
       
   122 				processInComment(data, area);
       
   123 			} else if (data.inPreprocessor) {
       
   124 				processInPreprocessor(data, area);
       
   125 			} else if (data.inString) {
       
   126 				processInString(data, area);
       
   127 			} else if (data.inChar) {
       
   128 				processInChar(data, area);
       
   129 			} else if (data.value == '/' && data.index < length) {
       
   130 				area = createCommentArea(data);
       
   131 			} else if (data.value == '\"') {
       
   132 				area = createStringArea(data);
       
   133 			} else if (data.value == '\'') {
       
   134 				area = createCharArea(data);
       
   135 			} else if (data.value == '#'
       
   136 					&& (data.index == 1 || parser.getSource().getChar(
       
   137 							data.index - 2) == '\n')) { // CodForChk_Dis_Magic
       
   138 				area = createPreprocessorArea(data);
       
   139 			}
       
   140 		}
       
   141 		return area;
       
   142 	}
       
   143 
       
   144 	/**
       
   145 	 * Gets the excluded area that contains given offset
       
   146 	 * 
       
   147 	 * @param offset
       
   148 	 *            the offset to the area
       
   149 	 * @return the area or null if offset does not hit any area
       
   150 	 */
       
   151 	SourceExcludedArea getArea(int offset) {
       
   152 		SourceExcludedArea retval;
       
   153 		int index = find(offset);
       
   154 		if (index >= 0) {
       
   155 			retval = excludedAreas.get(index);
       
   156 		} else {
       
   157 			retval = null;
       
   158 		}
       
   159 		return retval;
       
   160 	}
       
   161 
       
   162 	/**
       
   163 	 * Gets the list of excluded areas
       
   164 	 * 
       
   165 	 * @return the list of areas
       
   166 	 */
       
   167 	List<SourceExcludedArea> getAreas() {
       
   168 		return excludedAreas;
       
   169 	}
       
   170 
       
   171 	/**
       
   172 	 * Processes a quote (') character marking start of character area
       
   173 	 * 
       
   174 	 * @param data
       
   175 	 *            the search flags
       
   176 	 * @return the new area
       
   177 	 */
       
   178 	private SourceExcludedArea createCharArea(ExcludedAreaSearchData data) {
       
   179 		SourceExcludedArea area;
       
   180 		data.inChar = true;
       
   181 		area = new SourceExcludedArea(parser, data.index - 1,
       
   182 				SourceExcludedArea.CHARACTER);
       
   183 		return area;
       
   184 	}
       
   185 
       
   186 	/**
       
   187 	 * Processes a double quote (") character marking start of string area
       
   188 	 * 
       
   189 	 * @param data
       
   190 	 *            the search flags
       
   191 	 * @return the new area
       
   192 	 */
       
   193 	private SourceExcludedArea createStringArea(ExcludedAreaSearchData data) {
       
   194 		SourceExcludedArea area;
       
   195 		data.inString = true;
       
   196 		area = new SourceExcludedArea(parser, data.index - 1,
       
   197 				SourceExcludedArea.STRING);
       
   198 		return area;
       
   199 	}
       
   200 
       
   201 	/**
       
   202 	 * Processes a forward slash (/) character marking start of comment
       
   203 	 * 
       
   204 	 * @param data
       
   205 	 *            the search flags
       
   206 	 * @return the comment object
       
   207 	 * @throws SourceParserException
       
   208 	 *             if processing fails
       
   209 	 */
       
   210 	private SourceExcludedArea createCommentArea(ExcludedAreaSearchData data)
       
   211 			throws SourceParserException {
       
   212 		SourceExcludedArea area;
       
   213 		char next = parser.getSource().getChar(data.index);
       
   214 		if (next == '/') {
       
   215 			data.inLineComment = true;
       
   216 			area = new SourceExcludedArea(parser, data.index - 1,
       
   217 					SourceExcludedArea.LINE_COMMENT);
       
   218 			data.index++;
       
   219 		} else if (next == '*') {
       
   220 			data.inComment = true;
       
   221 			area = new SourceExcludedArea(parser, data.index - 1,
       
   222 					SourceExcludedArea.MULTILINE_COMMENT);
       
   223 			data.index++;
       
   224 		} else {
       
   225 			area = null;
       
   226 		}
       
   227 		return area;
       
   228 	}
       
   229 
       
   230 	/**
       
   231 	 * Processes a preprocessor definition
       
   232 	 * 
       
   233 	 * @param data
       
   234 	 *            the search flags
       
   235 	 * @return the preprocessor area representation
       
   236 	 */
       
   237 	private SourceExcludedArea createPreprocessorArea(
       
   238 			ExcludedAreaSearchData data) {
       
   239 		SourceExcludedArea area = new SourceExcludedArea(parser,
       
   240 				data.index - 1, SourceExcludedArea.PREPROCESSOR_DEFINITION);
       
   241 		data.inPreprocessor = true;
       
   242 		return area;
       
   243 	}
       
   244 
       
   245 	/**
       
   246 	 * Processes a character that belongs to '' area
       
   247 	 * 
       
   248 	 * @param data
       
   249 	 *            the search flags
       
   250 	 * @param area
       
   251 	 *            the area under processing
       
   252 	 * @throws SourceParserException
       
   253 	 *             if processing fails
       
   254 	 */
       
   255 	private void processInChar(ExcludedAreaSearchData data,
       
   256 			SourceExcludedArea area) throws SourceParserException {
       
   257 		// The check range is used to limit the effect of unterminated '
       
   258 		if ((data.value == '\'' && parser.getSource().getChar(data.index - 2) != '\\') // CodForChk_Dis_Magic
       
   259 				|| data.index - area.getOffset() > CHAR_CHECK_RANGE) {
       
   260 			data.inChar = false;
       
   261 			area.setLength(data.index - area.getOffset());
       
   262 			excludedAreas.add(area);
       
   263 		}
       
   264 	}
       
   265 
       
   266 	/**
       
   267 	 * Processes a character that belongs to "" area
       
   268 	 * 
       
   269 	 * @param data
       
   270 	 *            the search flags
       
   271 	 * @param area
       
   272 	 *            the area under processing
       
   273 	 * @throws SourceParserException
       
   274 	 *             if processing fails
       
   275 	 */
       
   276 	private void processInString(ExcludedAreaSearchData data,
       
   277 			SourceExcludedArea area) throws SourceParserException {
       
   278 		// Strings end with " unless escaped with \" (except \\")
       
   279 		if (data.value == '\"') {
       
   280 			if (parser.getSource().getChar(data.index - 2) != '\\' // CodForChk_Dis_Magic
       
   281 					|| parser.getSource().getChar(data.index - 3) == '\\') { // CodForChk_Dis_Magic
       
   282 				data.inString = false;
       
   283 				area.setLength(data.index - area.getOffset());
       
   284 				excludedAreas.add(area);
       
   285 			}
       
   286 		}
       
   287 	}
       
   288 
       
   289 	/**
       
   290 	 * Processes a character that belongs to multi-line comment
       
   291 	 * 
       
   292 	 * @param data
       
   293 	 *            the search flags
       
   294 	 * @param area
       
   295 	 *            the area under processing
       
   296 	 * @throws SourceParserException
       
   297 	 *             if processing fails
       
   298 	 */
       
   299 	private void processInComment(ExcludedAreaSearchData data,
       
   300 			SourceExcludedArea area) throws SourceParserException {
       
   301 		// Comments end with */
       
   302 		if (data.value == '*') {
       
   303 			if (data.index < parser.getSource().getLength()
       
   304 					&& parser.getSource().getChar(data.index) == '/') {
       
   305 				data.index++;
       
   306 				data.inComment = false;
       
   307 				area.setLength(data.index - area.getOffset());
       
   308 				excludedAreas.add(area);
       
   309 			}
       
   310 		}
       
   311 	}
       
   312 
       
   313 	/**
       
   314 	 * Processes a character that belongs to line comment
       
   315 	 * 
       
   316 	 * @param data
       
   317 	 *            the search flags
       
   318 	 * @param area
       
   319 	 *            the area under processing
       
   320 	 */
       
   321 	private void processInLineComment(ExcludedAreaSearchData data,
       
   322 			SourceExcludedArea area) {
       
   323 		if (data.value == '\n') {
       
   324 			data.inLineComment = false;
       
   325 			area.setLength(data.index - area.getOffset());
       
   326 			excludedAreas.add(area);
       
   327 		}
       
   328 	}
       
   329 
       
   330 	/**
       
   331 	 * Processes a character that belongs to preprocessor definition
       
   332 	 * 
       
   333 	 * @param data
       
   334 	 *            the search flags
       
   335 	 * @param area
       
   336 	 *            the area under processing
       
   337 	 * @throws SourceParserException
       
   338 	 *             if processing fails
       
   339 	 */
       
   340 	private void processInPreprocessor(ExcludedAreaSearchData data,
       
   341 			SourceExcludedArea area) throws SourceParserException {
       
   342 		if (data.value == '\n') {
       
   343 			char prev = parser.getSource().getChar(data.index - 2); // CodForChk_Dis_Magic
       
   344 			char prev2 = parser.getSource().getChar(data.index - 3); // CodForChk_Dis_Magic
       
   345 			if (!((prev == '\\') || (prev == '\r' && prev2 == '\\'))) {
       
   346 				data.inPreprocessor = false;
       
   347 				area.setLength(data.index - area.getOffset());
       
   348 				excludedAreas.add(area);
       
   349 			}
       
   350 		}
       
   351 	}
       
   352 }