/******************************************************************************* * Copyright (c) 2007, 2015 Wind River Systems, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Markus Schorn - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.internal.core.parser.scanner; import java.util.Calendar; import org.eclipse.cdt.core.dom.ILinkage; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IMacroBinding; import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.parser.IToken; import org.eclipse.cdt.core.parser.Keywords; import org.eclipse.cdt.core.parser.OffsetLimitReachedException; import org.eclipse.cdt.internal.core.dom.Linkage; import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions; import com.ibm.icu.text.DateFormatSymbols; /** * Models macros used by the preprocessor * @since 5.0 */ abstract class PreprocessorMacro implements IMacroBinding { final private char[] fName; public PreprocessorMacro(char[] name) { fName= name; } @Override final public ILinkage getLinkage() { return Linkage.NO_LINKAGE; } @Override final public char[] getNameCharArray() { return fName; } @Override final public String getName() { return new String(fName); } @Override public IScope getScope() { return null; } @Override public IBinding getOwner() { return null; } @Override public boolean isFunctionStyle() { return false; } @Override public char[][] getParameterList() { return null; } @Override public char[][] getParameterPlaceholderList() { return null; } @Override public <T> T getAdapter(Class<T> clazz) { return null; } /** * Returns {@link FunctionStyleMacro#NO_VAARGS} */ int hasVarArgs() { return FunctionStyleMacro.NO_VAARGS; } @Override public String toString() { char[][] p= getParameterList(); if (p == null) { return getName(); } StringBuffer buf= new StringBuffer(); buf.append(getNameCharArray()); buf.append('('); for (int i = 0; i < p.length; i++) { if (i > 0) { buf.append(','); } buf.append(p[i]); } buf.append(')'); return buf.toString(); } public abstract TokenList getTokens(MacroDefinitionParser parser, LexerOptions lexOptions, MacroExpander expander); } class ObjectStyleMacro extends PreprocessorMacro { private final AbstractCharArray fExpansion; final int fExpansionOffset; final int fEndOffset; private TokenList fExpansionTokens; public ObjectStyleMacro(char[] name, char[] expansion) { this(name, 0, expansion.length, null, new CharArray(expansion)); } public ObjectStyleMacro(char[] name, int expansionOffset, int endOffset, TokenList expansion, AbstractCharArray source) { super(name); fExpansionOffset= expansionOffset; fEndOffset= endOffset; fExpansion= source; fExpansionTokens= expansion; if (expansion != null) { setSource(expansion.first()); } } public int getExpansionOffset() { return fExpansionOffset; } public int getExpansionEndOffset() { return fEndOffset; } private void setSource(Token t) { final int shift= -fExpansionOffset; while (t != null) { t.fSource= this; t.shiftOffset(shift); t= (Token) t.getNext(); } } @Override public char[] getExpansion() { return MacroDefinitionParser.getExpansion(fExpansion, fExpansionOffset, fEndOffset); } @Override public char[] getExpansionImage() { final int length = fEndOffset - fExpansionOffset; char[] result= new char[length]; fExpansion.arraycopy(fExpansionOffset, result, 0, length); return result; } @Override public TokenList getTokens(MacroDefinitionParser mdp, LexerOptions lexOptions, MacroExpander expander) { if (fExpansionTokens == null) { fExpansionTokens= new TokenList(); Lexer lex= new Lexer(fExpansion, fExpansionOffset, fEndOffset, lexOptions, ILexerLog.NULL, this); try { lex.nextToken(); // consume the start token mdp.parseExpansion(lex, ILexerLog.NULL, getNameCharArray(), getParameterPlaceholderList(), fExpansionTokens); } catch (OffsetLimitReachedException e) { } } return fExpansionTokens; } @Override public final boolean isDynamic() { return false; } } class FunctionStyleMacro extends ObjectStyleMacro { public static final int NO_VAARGS = 0; // M(a) public static final int VAARGS = 1; // M(...) public static final int NAMED_VAARGS= 2; // M(a...) final private char[][] fParamList; final private int fHasVarArgs; private char[] fSignature; public FunctionStyleMacro(char[] name, char[][] paramList, int hasVarArgs, char[] expansion) { this(name, paramList, hasVarArgs, 0, expansion.length, null, new CharArray(expansion)); } public FunctionStyleMacro(char[] name, char[][] paramList, int hasVarArgs, AbstractCharArray expansion, int expansionOffset, int expansionEndOffset) { this(name, paramList, hasVarArgs, expansionOffset, expansionEndOffset, null, expansion); } public FunctionStyleMacro(char[] name, char[][] paramList, int hasVarArgs, int expansionFileOffset, int endFileOffset, TokenList expansion, AbstractCharArray source) { super(name, expansionFileOffset, endFileOffset, expansion, source); fParamList = paramList; fHasVarArgs= hasVarArgs; } @Override public char[][] getParameterList() { final int length = fParamList.length; if (fHasVarArgs == NO_VAARGS || length == 0) { return fParamList; } char[][] result= new char[length][]; System.arraycopy(fParamList, 0, result, 0, length - 1); if (fHasVarArgs == VAARGS) { result[length - 1]= Keywords.cpELLIPSIS; } else { final char[] param= fParamList[length - 1]; final int plen= param.length; final int elen = Keywords.cpELLIPSIS.length; final char[] rp= new char[plen + elen]; System.arraycopy(param, 0, rp, 0, plen); System.arraycopy(Keywords.cpELLIPSIS, 0, rp, plen, elen); result[length - 1]= rp; } return result; } @Override public char[][] getParameterPlaceholderList() { return fParamList; } public char[] getSignature() { if (fSignature != null) { return fSignature; } StringBuffer result= new StringBuffer(); result.append(getName()); result.append('('); final int lastIdx= fParamList.length - 1; if (lastIdx >= 0) { for (int i = 0; i < lastIdx; i++) { result.append(fParamList[i]); result.append(','); } switch (fHasVarArgs) { case VAARGS: result.append(Keywords.cpELLIPSIS); break; case NAMED_VAARGS: result.append(fParamList[lastIdx]); result.append(Keywords.cpELLIPSIS); break; default: result.append(fParamList[lastIdx]); break; } } result.append(')'); final int len= result.length(); final char[] sig= new char[len]; result.getChars(0, len, sig, 0); fSignature= sig; return sig; } /** * Returns one of {@link FunctionStyleMacro#NO_VAARGS}, {@link #VAARGS} or {@link #NAMED_VAARGS}. */ @Override int hasVarArgs() { return fHasVarArgs; } @Override public boolean isFunctionStyle() { return true; } } final class UndefinedMacro extends PreprocessorMacro { public UndefinedMacro(char[] name) { super(name); } @Override public TokenList getTokens(MacroDefinitionParser parser, LexerOptions lexOptions, MacroExpander expander) { return null; } @Override public char[] getExpansion() { return null; } @Override public char[] getExpansionImage() { return null; } @Override public boolean isDynamic() { return false; } } abstract class DynamicMacro extends PreprocessorMacro { public DynamicMacro(char[] name) { super(name); } @Override public final char[] getExpansion() { return getExpansionImage(); } public abstract Token execute(MacroExpander expander); @Override public TokenList getTokens(MacroDefinitionParser mdp, LexerOptions lexOptions, MacroExpander expander) { TokenList result= new TokenList(); result.append(execute(expander)); return result; } final protected void append(StringBuilder buffer, int value) { if (value < 10) buffer.append("0"); //$NON-NLS-1$ buffer.append(value); } @Override public final boolean isDynamic() { return true; } } final class DateMacro extends DynamicMacro { DateMacro(char[] name) { super(name); } @Override public Token execute(MacroExpander expander) { return new TokenWithImage(IToken.tSTRING, null, 0, 0, createDate()); } private char[] createDate() { char[] charArray; StringBuilder buffer = new StringBuilder("\""); //$NON-NLS-1$ Calendar cal = Calendar.getInstance(); DateFormatSymbols dfs= new DateFormatSymbols(); buffer.append(dfs.getShortMonths()[cal.get(Calendar.MONTH)]); buffer.append(" "); //$NON-NLS-1$ append(buffer, cal.get(Calendar.DAY_OF_MONTH)); buffer.append(" "); //$NON-NLS-1$ buffer.append(cal.get(Calendar.YEAR)); buffer.append("\""); //$NON-NLS-1$ charArray = buffer.toString().toCharArray(); return charArray; } @Override public char[] getExpansionImage() { return createDate(); } } final class FileMacro extends DynamicMacro { FileMacro(char[] name) { super(name); } @Override public Token execute(MacroExpander expander) { StringBuffer buffer = new StringBuffer("\""); //$NON-NLS-1$ buffer.append(expander.getCurrentFilename().replace("\\", "\\\\")); //$NON-NLS-1$//$NON-NLS-2$ buffer.append('\"'); return new TokenWithImage(IToken.tSTRING, null, 0, 0, buffer.toString().toCharArray()); } @Override public char[] getExpansionImage() { return "\"file\"".toCharArray(); //$NON-NLS-1$ } } final class LineMacro extends DynamicMacro { LineMacro(char[] name) { super(name); } @Override public Token execute(MacroExpander expander) { int lineNumber= expander.getCurrentLineNumber(); return new TokenWithImage(IToken.tINTEGER, null, 0, 0, Long.toString(lineNumber).toCharArray()); } @Override public char[] getExpansionImage() { return new char[] {'1'}; } } final class TimeMacro extends DynamicMacro { TimeMacro(char[] name) { super(name); } @Override public Token execute(MacroExpander expander) { return new TokenWithImage(IToken.tSTRING, null, 0, 0, createDate()); } private char[] createDate() { StringBuilder buffer = new StringBuilder("\""); //$NON-NLS-1$ Calendar cal = Calendar.getInstance(); append(buffer, cal.get(Calendar.HOUR_OF_DAY)); buffer.append(":"); //$NON-NLS-1$ append(buffer, cal.get(Calendar.MINUTE)); buffer.append(":"); //$NON-NLS-1$ append(buffer, cal.get(Calendar.SECOND)); buffer.append("\""); //$NON-NLS-1$ return buffer.toString().toCharArray(); } @Override public char[] getExpansionImage() { return createDate(); } } final class CounterMacro extends DynamicMacro { private static final char[] ZERO = {'0'}; private long fValue; CounterMacro(char[] name) { super(name); } @Override public Token execute(MacroExpander expander) { return new TokenWithImage(IToken.tINTEGER, null, 0, 0, String.valueOf(fValue++).toCharArray()); } @Override public char[] getExpansionImage() { return ZERO; } }