diff -r 14dc2103a631 -r ed1c9f64298a trace/tracebuilder/com.nokia.tracebuilder/src/com/nokia/tracebuilder/source/SourceParameterTokenizer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trace/tracebuilder/com.nokia.tracebuilder/src/com/nokia/tracebuilder/source/SourceParameterTokenizer.java Wed Jun 23 14:35:40 2010 +0300 @@ -0,0 +1,419 @@ +/* +* 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: +* +* Parameter tokenizer is used to parse function parameters lists +* +*/ +package com.nokia.tracebuilder.source; + +import java.util.List; + +/** + * Parameter tokenizer is used to parse function parameters lists + * + */ +public class SourceParameterTokenizer { + + /** + * The source parser + */ + private SourceParser parser; + + /** + * The offset where to start the tokenizer + */ + private int offset; + + /** + * Slip next whitespace + */ + private boolean skipNextWhiteSpace; + + /** + * Constructor + * + * @param parser + * the source parser + * @param offset + * offset to the start of parameter + */ + public SourceParameterTokenizer(SourceParser parser, int offset) { + this.parser = parser; + this.offset = offset; + } + + /** + * Parses a list of parameters (a, b, c) and stores the values into the + * given list. + * + * @param list + * the list of parameters + * @param findSeparator + * if true, the processing stops after ';' or '{' character. If + * false, processing stops after ')' at end of parameters + * @return index at end of parameters + * @throws SourceParserException + * if processing fails + */ + public int tokenize(List list, boolean findSeparator) + throws SourceParserException { + TokenizerSearchData data = new TokenizerSearchData(); + data.itr = parser.createIterator(offset, SourceParser.SKIP_WHITE_SPACES + | SourceParser.SKIP_COMMENTS); + boolean finished = false; + while (data.itr.hasNext() && !finished) { + data.value = data.itr.next(); + if (!data.inQuotes && data.value == '\"') { + data.inQuotes = true; + data.hasData = true; + } else if (data.inQuotes) { + processInQuotesChar(data); + } else if (data.complete) { + processEndOfParametersChar(data); + } else if (data.value == '(') { + processOpeningBracket(data); + } else if (data.value == ',' || data.value == ')') { + processCommaOrClosingBracket(list, data); + } else if (data.value == ';' || data.value == '{' + || data.value == '}') { + throw new SourceParserException( + SourceErrorCodes.UNEXPECTED_PARAMETER_SEPARATOR); + } else { + // Raises a flag that there is some data. processOpeningBracket + // no longer interprets the next bracket as opening bracket + if (data.openBracketCount > 0) { + data.hasData = true; + } + } + finished = ((data.complete && !findSeparator) || (data.endFound && findSeparator)); + } + if (!data.complete) { + throw new SourceParserException( + SourceErrorCodes.UNEXPECTED_END_OF_FILE); + } + if (data.openBracketCount != 0) { + throw new SourceParserException(SourceErrorCodes.BRACKET_MISMATCH); + } + return data.itr.currentIndex() + 1; + } + + /** + * Parses list of parameters with types (int a, int b, int c) and stores the + * values into the given list. + * + * @param list + * the list of parameters + * @return index at end of parameters + * @throws SourceParserException + * if processing fails + */ + public int tokenizeTyped(List list) + throws SourceParserException { + TokenizerSearchData data = new TokenizerSearchData(); + + try { + data.itr = parser + .createIterator(offset, SourceParser.SKIP_WHITE_SPACES + | SourceParser.SKIP_COMMENTS); + data.sourceParameter = new SourceParameter(); + while (data.itr.hasNext() && !data.complete) { + data.value = data.itr.next(); + + // Check if there was array start or end character and then + // space. It would mean that the parameter continues and more + // should be parsed. + if (skipNextWhiteSpace) { + skipNextWhiteSpace = false; + if (data.itr.hasSkipped()) { + data.value = data.itr.next(); + } + } + + if (data.value == '\"') { + throw new SourceParserException( + SourceErrorCodes.UNEXPECTED_QUOTE_CHARACTER); + } else if (data.value == '(') { + processOpeningBracket(data); + } else if (data.value == ',' || data.value == ')') { + processCommaOrClosingBracket(list, data); + } else if (data.value == ';' || data.value == '{' + || data.value == '}') { + throw new SourceParserException( + SourceErrorCodes.UNEXPECTED_PARAMETER_SEPARATOR); + + // Array start or end character. + } else if (data.value == '<' || data.value == '>') { + skipNextWhiteSpace = true; + } else if (data.itr.hasSkipped()) { + processNameValueSeparator(data); + } + } + if (!data.complete) { + throw new SourceParserException( + SourceErrorCodes.UNEXPECTED_END_OF_FILE); + } + } catch (SourceParserException e) { + // Resets all source locations if parser fails + for (int i = 0; i < list.size(); i++) { + list.get(i).getSourceLocation().dereference(); + } + throw e; + } + return data.itr.currentIndex() + 1; + } + + /** + * Processes a separator character and updates the current SourceParameter + * object in the search data + * + * @param data + * the search data + * @throws SourceParserException + * if processing fails + */ + private void processNameValueSeparator(TokenizerSearchData data) + throws SourceParserException { + // If the parameter is empty, the previous index will point + // to index preceeding tagStartIndex + int previous = data.itr.previousIndex(); + if (previous >= data.tagStartIndex) { + int endIndex = previous + 1; + if (data.sourceParameter.getType() == null) { + processNameValueSeparatorNoType(data, endIndex); + } else if (data.sourceParameter.getName() == null) { + processNameValueSeparatorNoName(data, endIndex); + } + data.tagStartIndex = data.itr.currentIndex(); + } + } + + /** + * Processes a name-value separator when there is no name + * + * @param data + * the search data + * @param endIndex + * the end index of the parameters + * @throws SourceParserException + * if processing fails + */ + private void processNameValueSeparatorNoName(TokenizerSearchData data, + int endIndex) throws SourceParserException { + String name = parser.getSource().get(data.tagStartIndex, + endIndex - data.tagStartIndex); + boolean startFound = false; + int start = 0; + int end = name.length(); + for (int i = 0; i < name.length(); i++) { + char c = name.charAt(i); + if (c == '&' || c == '*') { + if (c == '&') { + data.sourceParameter.setReference(); + } else { + data.sourceParameter.addPointer(); + } + if (!startFound) { + start++; + } else { + end--; + } + } else { + startFound = true; + } + } + name = name.substring(start, end); + if (name.length() > 0) { + if (isParameterTypeQualifier(name)) { + // Qualifiers between type and name are ignored + // For example TInt const* aValue + } else { + data.sourceParameter.setName(name); + } + } + } + + /** + * Processes a name-value separator when there is no value + * + * @param data + * the search data + * @param endIndex + * the end index of the parameters + * @throws SourceParserException + * if processing fails + */ + private void processNameValueSeparatorNoType(TokenizerSearchData data, + int endIndex) throws SourceParserException { + String type = parser.getSource().get(data.tagStartIndex, + endIndex - data.tagStartIndex); + if (isParameterTypeQualifier(type)) { + data.sourceParameter.addQualifier(type); + } else { + for (int i = type.length() - 1; i >= 0; i--) { + if (type.charAt(i) == '&') { + data.sourceParameter.setReference(); + if (i == 0) { + type = ""; //$NON-NLS-1$ + } + } else if (type.charAt(i) == '*') { + data.sourceParameter.addPointer(); + if (i == 0) { + type = ""; //$NON-NLS-1$ + } + } else { + if (i != type.length() - 1) { + type = type.substring(0, i + 1); + } + i = -1; + } + } + if (type.length() > 0) { + // Remove spaces + type = type.replace(" ", ""); //$NON-NLS-1$ //$NON-NLS-2$ + data.sourceParameter.setType(type); + } + } + } + + /** + * Checks if parameter type if a qualifier or not + * + * @param type + * the type to be checked + * @return true if qualifier, false if not + */ + private boolean isParameterTypeQualifier(String type) { + boolean retval = false; + for (String element : SourceConstants.PARAMETER_QUALIFIERS) { + if (type.equals(element)) { + retval = true; + } + } + return retval; + } + + /** + * Processes a parameter separator or closing bracket + * + * @param list + * the list of existing parameters + * @param data + * the search data + * @throws SourceParserException + * if invalid character is encountered + */ + @SuppressWarnings("unchecked") + private void processCommaOrClosingBracket(List list, + TokenizerSearchData data) throws SourceParserException { + // This method is called from both tokenize functions. One uses + // List and other List + // Thus this uses List and @SuppressWarnings + if (data.openBracketCount == data.initialBracketCount) { + if (data.sourceParameter != null) { + // If processing typed parameter list, the name and type are + // stored into a SourceParameter object, which is then added + // to list + processNameValueSeparator(data); + if (data.sourceParameter.getType() != null) { + SourceLocation location = new SourceLocation(parser, + data.paramStartIndex, data.itr.currentIndex() + - data.paramStartIndex); + data.sourceParameter.setSourceLocation(location); + list.add(data.sourceParameter); + data.sourceParameter = new SourceParameter(); + } + } else { + // In this case the list contains strings. + int previous = data.itr.previousIndex(); + if (previous >= data.tagStartIndex) { + int endIndex = data.itr.previousIndex() + 1; + list.add(parser.getSource().get(data.tagStartIndex, + endIndex - data.tagStartIndex)); + } else { + list.add(""); //$NON-NLS-1$ + } + } + if (data.value == ')') { + data.complete = true; + data.openBracketCount--; + } else { + data.tagStartIndex = data.itr.nextIndex(); + data.paramStartIndex = data.tagStartIndex; + } + } else if (data.openBracketCount > data.initialBracketCount) { + if (data.value == ')') { + data.openBracketCount--; + } + } else { + if (data.value == ')') { + throw new SourceParserException( + SourceErrorCodes.BRACKET_MISMATCH); + } + throw new SourceParserException( + SourceErrorCodes.UNEXPECTED_PARAMETER_SEPARATOR); + } + } + + /** + * Processes an opening bracket + * + * @param data + * the search data + */ + private void processOpeningBracket(TokenizerSearchData data) { + data.openBracketCount++; + if (!data.hasData) { + // The number of initial '(' characters is stored. The + // parameters are assumed to end when the corresponding ')' + // character is encountered + data.tagStartIndex = data.itr.nextIndex(); + data.paramStartIndex = data.tagStartIndex; + data.initialBracketCount = data.openBracketCount; + } + } + + /** + * Process a character when in quotes + * + * @param data + * the search data + */ + private void processInQuotesChar(TokenizerSearchData data) { + if (data.value == '\"' && data.previousValue != '\\') { + data.inQuotes = false; + } + data.previousValue = data.value; + } + + /** + * Processes a character found after the closing bracket + * + * @param data + * the data + * @throws SourceParserException + * if invalid characters are found + */ + private void processEndOfParametersChar(TokenizerSearchData data) + throws SourceParserException { + if (data.value == ';' || data.value == '{') { + data.endFound = true; + } else if (data.value == ')') { + data.openBracketCount--; + } else if (!Character.isWhitespace(data.value)) { + throw new SourceParserException(SourceErrorCodes.BRACKET_MISMATCH); + } + } + +} \ No newline at end of file