tracesrv/tracecompiler/src/com.nokia.tracecompiler/src/com/nokia/tracecompiler/source/SourceParser.java
changeset 56 aa2539c91954
parent 41 838cdffd57ce
equal deleted inserted replaced
54:a151135b0cf9 56:aa2539c91954
       
     1 /*
       
     2 * Copyright (c) 2008-2010 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 C++ source files
       
    17 *
       
    18 */
       
    19 package com.nokia.tracecompiler.source;
       
    20 
       
    21 import java.util.ArrayList;
       
    22 import java.util.List;
       
    23 
       
    24 /**
       
    25  * Parser for C++ source files. Commented and quoted areas are located during
       
    26  * the construction of this object and those areas are excluded from the
       
    27  * searches.
       
    28  * 
       
    29  */
       
    30 public class SourceParser {
       
    31 
       
    32 	/**
       
    33 	 * Skip white spaces. Does not apply to string searches
       
    34 	 */
       
    35 	public final static int SKIP_WHITE_SPACES = 0x01; // CodForChk_Dis_Magic
       
    36 
       
    37 	/**
       
    38 	 * Skip string areas
       
    39 	 */
       
    40 	public final static int SKIP_STRINGS = 0x02; // CodForChk_Dis_Magic
       
    41 
       
    42 	/**
       
    43 	 * Search / iterate backwards
       
    44 	 */
       
    45 	public final static int BACKWARD_SEARCH = 0x04; // CodForChk_Dis_Magic
       
    46 
       
    47 	/**
       
    48 	 * Ignore character case in string searches
       
    49 	 */
       
    50 	public final static int IGNORE_CASE = 0x08; // CodForChk_Dis_Magic
       
    51 
       
    52 	/**
       
    53 	 * Skip commented areas
       
    54 	 */
       
    55 	public final static int SKIP_COMMENTS = 0x10; // CodForChk_Dis_Magic
       
    56 
       
    57 	/**
       
    58 	 * Skip preprocessor definitions
       
    59 	 */
       
    60 	public final static int SKIP_PREPROCESSOR = 0x80; // CodForChk_Dis_Magic
       
    61 
       
    62 	/**
       
    63 	 * Match beginning of word flag
       
    64 	 */
       
    65 	public final static int MATCH_WORD_BEGINNING = 0x20; // CodForChk_Dis_Magic
       
    66 
       
    67 	/**
       
    68 	 * Match end of word flag
       
    69 	 */
       
    70 	public final static int MATCH_WORD_END = 0x40; // CodForChk_Dis_Magic
       
    71 
       
    72 	/**
       
    73 	 * Match whole word flag
       
    74 	 */
       
    75 	public final static int MATCH_WHOLE_WORD = MATCH_WORD_BEGINNING
       
    76 			| MATCH_WORD_END;
       
    77 
       
    78 	/**
       
    79 	 * Ignore all special areas during search
       
    80 	 */
       
    81 	public final static int SKIP_ALL = SKIP_WHITE_SPACES | SKIP_STRINGS
       
    82 			| SKIP_COMMENTS | SKIP_PREPROCESSOR;
       
    83 
       
    84 	/**
       
    85 	 * Data to be searched.
       
    86 	 */
       
    87 	private SourceDocumentInterface source;
       
    88 
       
    89 	/**
       
    90 	 * List of source locations
       
    91 	 */
       
    92 	private ArrayList<SourceLocation> locations;
       
    93 
       
    94 	/**
       
    95 	 * Document factory for creating locations
       
    96 	 */
       
    97 	private SourceDocumentFactory documentFactory;
       
    98 
       
    99 	/**
       
   100 	 * Excluded area parser
       
   101 	 */
       
   102 	private ExcludedAreaParser excludedAreaParser;
       
   103 
       
   104 	/**
       
   105 	 * Context area parser
       
   106 	 */
       
   107 	private ContextAreaParser contextAreaParser;
       
   108 
       
   109 	/**
       
   110 	 * Function return value parser
       
   111 	 */
       
   112 	private FunctionReturnValueParser returnValueParser;
       
   113 
       
   114 	/**
       
   115 	 * Creates a new parser for given data
       
   116 	 * 
       
   117 	 * @param factory
       
   118 	 *            the document factory
       
   119 	 * @param sourceData
       
   120 	 *            the source data
       
   121 	 */
       
   122 	public SourceParser(SourceDocumentFactory factory, String sourceData) {
       
   123 		this(factory, factory.createDocument(sourceData));
       
   124 	}
       
   125 
       
   126 	/**
       
   127 	 * Creates a source parser from source document
       
   128 	 * 
       
   129 	 * @param factory
       
   130 	 *            the document factory
       
   131 	 * @param source
       
   132 	 *            the source document
       
   133 	 */
       
   134 	public SourceParser(SourceDocumentFactory factory,
       
   135 			SourceDocumentInterface source) {
       
   136 		this.documentFactory = factory;
       
   137 		this.source = source;
       
   138 		excludedAreaParser = new ExcludedAreaParser(this);
       
   139 		contextAreaParser = new ContextAreaParser(this);
       
   140 		returnValueParser = new FunctionReturnValueParser(this);
       
   141 		try {
       
   142 			findExcludedAreas();
       
   143 		} catch (SourceParserException e) {
       
   144 		}
       
   145 	}
       
   146 
       
   147 	/**
       
   148 	 * Gets the source document
       
   149 	 * 
       
   150 	 * @return the source
       
   151 	 */
       
   152 	public SourceDocumentInterface getSource() {
       
   153 		return source;
       
   154 	}
       
   155 
       
   156 	/**
       
   157 	 * Gets part of the source document data
       
   158 	 * 
       
   159 	 * @param start
       
   160 	 *            the start offset
       
   161 	 * @param length
       
   162 	 *            the data length
       
   163 	 * @return the data or null if offsets are not valid
       
   164 	 */
       
   165 	public String getData(int start, int length) {
       
   166 		String retval;
       
   167 		try {
       
   168 			retval = source.get(start, length);
       
   169 		} catch (SourceParserException e) {
       
   170 			retval = null;
       
   171 		}
       
   172 		return retval;
       
   173 	}
       
   174 
       
   175 	/**
       
   176 	 * Gets a character at given offset
       
   177 	 * 
       
   178 	 * @param offset
       
   179 	 *            the offset
       
   180 	 * @return the character
       
   181 	 */
       
   182 	public char getData(int offset) {
       
   183 		char retval;
       
   184 		try {
       
   185 			retval = source.getChar(offset);
       
   186 		} catch (SourceParserException e) {
       
   187 			retval = '\0';
       
   188 		}
       
   189 		return retval;
       
   190 	}
       
   191 
       
   192 	/**
       
   193 	 * Gets the source document length
       
   194 	 * 
       
   195 	 * @return the source length
       
   196 	 */
       
   197 	public int getDataLength() {
       
   198 		return source.getLength();
       
   199 	}
       
   200 
       
   201 	/**
       
   202 	 * Gets the line number of given offset
       
   203 	 * 
       
   204 	 * @param offset
       
   205 	 *            the offset
       
   206 	 * @return the line number or -1 if offset is not valid
       
   207 	 */
       
   208 	public int getLineNumber(int offset) {
       
   209 		int retval;
       
   210 		try {
       
   211 			retval = source.getLineOfOffset(offset) + 1;
       
   212 		} catch (SourceParserException e) {
       
   213 			retval = -1;
       
   214 		}
       
   215 		return retval;
       
   216 	}
       
   217 
       
   218 	/**
       
   219 	 * Starts a new string search from given offset
       
   220 	 * 
       
   221 	 * @param searchString
       
   222 	 *            the string to be searched
       
   223 	 * @param startOffset
       
   224 	 *            the offset to start of search
       
   225 	 * @param endOffset
       
   226 	 *            the end of search or -1 to search the whole document
       
   227 	 * @param searchFlags
       
   228 	 *            the search flags
       
   229 	 * @return the search object
       
   230 	 */
       
   231 	public SourceStringSearch startStringSearch(String searchString,
       
   232 			int startOffset, int endOffset, int searchFlags) {
       
   233 		return new SourceStringSearch(this, searchString, startOffset,
       
   234 				endOffset, searchFlags);
       
   235 	}
       
   236 
       
   237 	/**
       
   238 	 * Tokenizes the parameter list starting from next bracket. White spaces are
       
   239 	 * discarded. For example (a, b , c ) returns { "a", "b", "c" }. This method
       
   240 	 * is independent of the current string search and thus can be used during
       
   241 	 * one.
       
   242 	 * 
       
   243 	 * @param startIndex
       
   244 	 *            the index where to start
       
   245 	 * @param list
       
   246 	 *            the list where the parameters are added
       
   247 	 * @param findSeparator
       
   248 	 *            if true, the processing stops after ';' or '{' character. If
       
   249 	 *            false, processing stops after ')' at end of parameters
       
   250 	 * @return the offset at end of the parameters
       
   251 	 * @throws SourceParserException
       
   252 	 *             if parameters are not valid
       
   253 	 */
       
   254 	public int tokenizeParameters(int startIndex, List<String> list,
       
   255 			boolean findSeparator) throws SourceParserException {
       
   256 		SourceParameterTokenizer tokenizer = new SourceParameterTokenizer(this,
       
   257 				startIndex);
       
   258 		return tokenizer.tokenize(list, findSeparator);
       
   259 	}
       
   260 
       
   261 	/**
       
   262 	 * Parses the parameter list of given source context. Each entry added into
       
   263 	 * the list will be an instance of SourceParameter class. This method is
       
   264 	 * independent of the current string search and thus can be used during one.
       
   265 	 * 
       
   266 	 * @param parameterIndex
       
   267 	 *            the index where to start
       
   268 	 * @param list
       
   269 	 *            the list where the parameters are added
       
   270 	 * @return the offset at end of the parameters
       
   271 	 * @throws SourceParserException
       
   272 	 *             if context is not valid
       
   273 	 */
       
   274 	public int parseFunctionParameters(int parameterIndex, List<SourceParameter> list)
       
   275 			throws SourceParserException {
       
   276 		SourceParameterTokenizer tokenizer = new SourceParameterTokenizer(this,
       
   277 				parameterIndex);
       
   278 		return tokenizer.tokenizeTyped(list);
       
   279 	}
       
   280 
       
   281 	/**
       
   282 	 * Parses the return values of given source context
       
   283 	 * 
       
   284 	 * @param context
       
   285 	 *            the context to be parsed
       
   286 	 * @param list
       
   287 	 *            the list of return values
       
   288 	 */
       
   289 	void parseReturnValues(SourceContext context, List<SourceReturn> list) {
       
   290 		returnValueParser.parseReturnValues(context, list);
       
   291 	}
       
   292 
       
   293 	/**
       
   294 	 * Checks if the offset if within an excluded area
       
   295 	 * 
       
   296 	 * @param offset
       
   297 	 *            the offset
       
   298 	 * @return true if in excluded area
       
   299 	 */
       
   300 	public boolean isInExcludedArea(int offset) {
       
   301 		return findExcludedAreaIndex(offset) >= 0;
       
   302 	}
       
   303 
       
   304 	/**
       
   305 	 * Gets an excluded area
       
   306 	 * 
       
   307 	 * @param offset
       
   308 	 *            the data offset
       
   309 	 * @return the area or null
       
   310 	 */
       
   311 	public SourceExcludedArea getExcludedArea(int offset) {
       
   312 		return excludedAreaParser.getArea(offset);
       
   313 	}
       
   314 
       
   315 	/**
       
   316 	 * Creates a new source iterator
       
   317 	 * 
       
   318 	 * @param offset
       
   319 	 *            the offset where to start
       
   320 	 * @param iteratorFlags
       
   321 	 *            the flags for the iterator
       
   322 	 * @return the new iterator
       
   323 	 */
       
   324 	public SourceIterator createIterator(int offset, int iteratorFlags) {
       
   325 		return new SourceIterator(this, offset, iteratorFlags);
       
   326 	}
       
   327 
       
   328 	/**
       
   329 	 * Returns the context at given offset. This parses the source if it has not
       
   330 	 * been parsed before.
       
   331 	 * 
       
   332 	 * @param offset
       
   333 	 *            the offset to the source data
       
   334 	 * @return the context at the offset or null if no context exists
       
   335 	 */
       
   336 	public SourceContext getContext(int offset) {
       
   337 		SourceContext retval;
       
   338 		try {
       
   339 			retval = contextAreaParser.parseAndGet(offset);
       
   340 		} catch (SourceParserException e) {
       
   341 			retval = null;
       
   342 		}
       
   343 		return retval;
       
   344 	}
       
   345 
       
   346 	/**
       
   347 	 * Locates the start-of-line starting from given offset
       
   348 	 * 
       
   349 	 * @param offset
       
   350 	 *            the offset
       
   351 	 * @param cancelIfNotWhitespace
       
   352 	 *            flag that tells to stop processing and return the original
       
   353 	 *            value if a non-whitespace is found before start of line
       
   354 	 * @param stayInContext
       
   355 	 *            flag that tells to stay within the context offset currently
       
   356 	 *            resides. If this would come out of the context, this locates
       
   357 	 *            the start of the next line following offset
       
   358 	 * @return the start-of-line
       
   359 	 * @throws SourceParserException
       
   360 	 *             if the offset is not valid
       
   361 	 */
       
   362 	public int findStartOfLine(int offset, boolean cancelIfNotWhitespace,
       
   363 			boolean stayInContext) throws SourceParserException {
       
   364 		int retval = offset == 0 ? offset : offset - 1;
       
   365 		for (int i = retval; i >= 0; i--) {
       
   366 			char c = source.getChar(i);
       
   367 			if (source.getChar(i) == '\n') {
       
   368 				retval = i + 1;
       
   369 				i = -1;
       
   370 			} else if (cancelIfNotWhitespace && !Character.isWhitespace(c)) {
       
   371 				retval = offset;
       
   372 				i = -1;
       
   373 			}
       
   374 		}
       
   375 		if (stayInContext) {
       
   376 			SourceContext context = getContext(offset);
       
   377 			if (context != null && retval < context.getOffset()) {
       
   378 				retval = context.getOffset();
       
   379 				int end = context.getOffset() + context.getLength();
       
   380 				for (int i = retval; i < end; i++) {
       
   381 					if (source.getChar(i) == '\n') {
       
   382 						retval = i + 1;
       
   383 						i = end;
       
   384 					}
       
   385 				}
       
   386 			}
       
   387 		}
       
   388 		return retval;
       
   389 	}
       
   390 
       
   391 	/**
       
   392 	 * Finds the array index of the excluded area which contains the offset. If
       
   393 	 * none of the areas contain the offset, returns negative integer indicating
       
   394 	 * the index of the excluded area following the offset
       
   395 	 * 
       
   396 	 * @param offset
       
   397 	 *            the offset to the data
       
   398 	 * @return the excluded area index
       
   399 	 */
       
   400 	int findExcludedAreaIndex(int offset) {
       
   401 		return excludedAreaParser.find(offset);
       
   402 	}
       
   403 
       
   404 	/**
       
   405 	 * Finds the excluded source file areas. Excluded areas include comments and
       
   406 	 * quoted strings. Overwrites possible old areas.
       
   407 	 * 
       
   408 	 * @throws SourceParserException
       
   409 	 *             if parser fails
       
   410 	 */
       
   411 	public void findExcludedAreas() throws SourceParserException {
       
   412 		excludedAreaParser.parseAll();
       
   413 	}
       
   414 
       
   415 	/**
       
   416 	 * Gets the list of excluded areas
       
   417 	 * 
       
   418 	 * @return the list
       
   419 	 */
       
   420 	public List<SourceExcludedArea> getExcludedAreas() {
       
   421 		return excludedAreaParser.getAreas();
       
   422 	}
       
   423 
       
   424 	/**
       
   425 	 * Checks if the area is excluded with given flags
       
   426 	 * 
       
   427 	 * @param type
       
   428 	 *            the area type
       
   429 	 * @param flags
       
   430 	 *            the flags
       
   431 	 * @return true if skipped
       
   432 	 */
       
   433 	static boolean isExcluded(int type, int flags) {
       
   434 		boolean string = ((flags & SKIP_STRINGS) != 0)
       
   435 				&& (type == SourceExcludedArea.STRING);
       
   436 		boolean comment = ((flags & SKIP_COMMENTS) != 0)
       
   437 				&& (type == SourceExcludedArea.MULTILINE_COMMENT);
       
   438 		boolean linecomment = ((flags & SKIP_COMMENTS) != 0)
       
   439 				&& (type == SourceExcludedArea.LINE_COMMENT);
       
   440 		boolean preProcessor = ((flags & SKIP_PREPROCESSOR) != 0)
       
   441 				&& (type == SourceExcludedArea.PREPROCESSOR_DEFINITION);
       
   442 		return string || comment || linecomment || preProcessor;
       
   443 	}
       
   444 
       
   445 	/**
       
   446 	 * Adds a location to this parser
       
   447 	 * 
       
   448 	 * @param location
       
   449 	 *            the location
       
   450 	 */
       
   451 	void addLocation(SourceLocation location) {
       
   452 		if (locations == null) {
       
   453 			locations = new ArrayList<SourceLocation>();
       
   454 		}
       
   455 		locations.add(location);
       
   456 		if (source != null) {
       
   457 			source.addLocation(location.getLocation());
       
   458 		}
       
   459 	}
       
   460 
       
   461 	/**
       
   462 	 * Removes a location from this parser
       
   463 	 * 
       
   464 	 * @param location
       
   465 	 *            the location to be removed
       
   466 	 */
       
   467 	void removeLocation(SourceLocation location) {
       
   468 		if (locations != null) {
       
   469 			locations.remove(location);
       
   470 		}
       
   471 		if (source != null) {
       
   472 			source.removeLocation(location.getLocation());
       
   473 		}
       
   474 	}
       
   475 
       
   476 	/**
       
   477 	 * Gets the document framework
       
   478 	 * 
       
   479 	 * @return the document framework
       
   480 	 */
       
   481 	public SourceDocumentFactory getDocumentFramework() {
       
   482 		return documentFactory;
       
   483 	}
       
   484 
       
   485 }