Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 9b7988c9f62d5b05890d0b1d4e73a8e12e7c199e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*******************************************************************************
 * Copyright (c) 2007, 2008 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.ArrayList;

import org.eclipse.cdt.core.parser.IToken;
import org.eclipse.cdt.core.parser.OffsetLimitReachedException;

/**
 * Represents part of the input to the preprocessor. This may be a file or the result of a macro expansion.
 * @since 5.0
 */
final class ScannerContext {
	private static final Token END_TOKEN = new Token(IToken.tEND_OF_INPUT, null, 0, 0);

	public static final Integer BRANCH_IF = new Integer(0);
	public static final Integer BRANCH_ELIF = new Integer(1);
	public static final Integer BRANCH_ELSE = new Integer(2);
	public static final Integer BRANCH_END = new Integer(3);
	
	private final ILocationCtx fLocationCtx;
	private final ScannerContext fParent;
	private final Lexer fLexer;
	private ArrayList<Integer> fBranches= null;

	private Token fTokens;

	/**
	 * @param ctx 
	 * @param parent context to be used after this context is done.
	 */
	public ScannerContext(ILocationCtx ctx, ScannerContext parent, Lexer lexer) {
		fLocationCtx= ctx;
		fParent= parent;
		fLexer= lexer;
	}
	
	public ScannerContext(ILocationCtx ctx, ScannerContext parent, TokenList tokens) {
		fLocationCtx= ctx;
		fParent= parent;
		fLexer= null;
		fTokens= tokens.first();
	}

	/**
	 * Returns the location context associated with this scanner context.
	 */
	public final ILocationCtx getLocationCtx() {
		return fLocationCtx;
	}
	
	/**
	 * Returns the parent context which will be used after this context is finished.
	 * May return <code>null</code>.
	 */
	public final ScannerContext getParent() {
		return fParent;
	}

	/**
	 * Returns the lexer for this context.
	 */
	public final Lexer getLexer() {
		return fLexer;
	}

	/**
	 * Needs to be called whenever we change over to another branch of conditional 
	 * compilation. Returns whether the change is legal at this point or not.
	 */
	public final boolean changeBranch(Integer branchKind) {
		if (fBranches == null) {
			fBranches= new ArrayList<Integer>();
		}
		
		// an if starts a new conditional construct
		if (branchKind == BRANCH_IF) {
			fBranches.add(branchKind);
			return true;
		}
		// if we are not inside of an conditional there shouldn't be an #else, #elsif or #end
		final int pos= fBranches.size()-1;
		if (pos < 0) {
			return false;
		}
		// an #end just pops one construct.
		if (branchKind == BRANCH_END) {
			fBranches.remove(pos);
			return true;
		}
		// #elsif or #else cannot appear after another #else
		if (fBranches.get(pos) == BRANCH_ELSE) {
			return false;
		}
		// overwrite #if, #elsif with #elsif or #else
		fBranches.set(pos, branchKind);
		return true;
	}

	/** 
	 * Returns the current token from this context. When called before calling {@link #nextPPToken()} 
	 * a token of type {@link Lexer#tBEFORE_INPUT} will be returned.
	 * @since 5.0
	 */
	public final Token currentLexerToken() {
		if (fLexer != null) {
			return fLexer.currentToken();
		}
		if (fTokens != null) {
			return fTokens;
		}
		return END_TOKEN;
	}
	
	/** 
	 * Returns the next token from this context. 
	 */
	public Token nextPPToken() throws OffsetLimitReachedException {
		if (fLexer != null) {
			return fLexer.nextToken();
		}
		if (fTokens != null) {
			fTokens= (Token) fTokens.getNext();
		}
		return currentLexerToken();
	}
}

Back to the top