--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tracesrv/tracecompiler/src/com.nokia.tracecompiler/src/com/nokia/tracecompiler/source/SourceParameterTokenizer.java Fri Oct 08 14:56:39 2010 +0300
@@ -0,0 +1,440 @@
+/*
+* Copyright (c) 2010 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.tracecompiler.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<String> list, boolean findSeparator)
+ throws SourceParserException {
+ TokenizerSearchData data = new TokenizerSearchData();
+ data.itr = parser.createIterator(offset, SourceParser.SKIP_WHITE_SPACES
+ | SourceParser.SKIP_COMMENTS);
+ boolean bracketsOpened = false;
+ 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 == '(') {
+ bracketsOpened = true;
+ processOpeningBracket(data);
+ } else if (data.value == ',' || data.value == ')') {
+ processCommaOrClosingBracket(list, data);
+ } else if (data.value == ';' && data.openBracketCount != 0 || 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 (bracketsOpened && data.openBracketCount == 0) {
+ data.complete = true;
+ break;
+ }
+ }
+ 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<SourceParameter> 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 == '}') {
+ data.complete = true;
+ // Array start or end character.
+ } else if (data.value == '<' || data.value == '>') {
+ skipNextWhiteSpace = true;
+ } else if (data.itr.hasSkipped() && data.openBracketCount > 0) {
+ 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<String> and other List<SourceParameter>
+ // Thus this uses List and @SuppressWarnings
+ if (data.value == ')') {
+ data.openBracketCount--;
+ }
+
+ if (data.value == ',') {
+ //we may have the case of OstTraceDef1( OST_TRACE_CATEGORY_ALL, TRACE_FATAL, TEST_OstTraceDef1, "EOstTraceDef1 - %u" , f(a,b));
+ //when processing the comma in f(a,b) that should not count as parameter separator
+ if (data.openBracketCount >1 ) {
+ return;
+ }
+ }
+
+ if (data.value == ',' || data.openBracketCount == 0) {
+ //we have another parameter
+ 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();
+ String tracepoint = ""; //$NON-NLS-1$
+ if (previous >= data.tagStartIndex) {
+ int endIndex = data.itr.previousIndex() + 1;
+ tracepoint = parser.getSource().get(data.tagStartIndex,
+ endIndex - data.tagStartIndex);
+ list.add(tracepoint);
+ } else {
+ list.add(tracepoint);
+ }
+ }
+
+ // In case like below we have parsed all parameters and data is completed if next character after ')' is ':'
+ // and open bracket count is 0:
+ // CNpeSendData::CNpeSendData(RMeDriver* aDriver, TUint16 aMaxMsgLength): CActive(EPriorityStandard),
+ // iDriver(aDriver),
+ // iMaxMsgLength(aMaxMsgLength)
+ if (data.itr.hasNext()){
+ char nextChar = data.itr.peek();
+
+ if (data.value == ')' && nextChar == ':' && data.openBracketCount == 0) {
+ data.complete = true;
+ }
+ }
+
+ if (data.value == ',') {
+ data.tagStartIndex = data.itr.nextIndex();
+ data.paramStartIndex = data.tagStartIndex;
+ }
+ }
+ }
+
+ /**
+ * Processes an opening bracket
+ *
+ * @param data
+ * the search data
+ */
+ private void processOpeningBracket(TokenizerSearchData data) {
+ data.openBracketCount++;
+ if (!data.hasData && data.openBracketCount == 1 ) {
+ // 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);
+ }
+ }
+
+}