001/* 002 * Anarres C Preprocessor 003 * Copyright (c) 2007-2015, Shevek 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 014 * or implied. See the License for the specific language governing 015 * permissions and limitations under the License. 016 */ 017package org.anarres.cpp; 018 019import java.io.Closeable; 020import java.io.IOException; 021import java.io.Reader; 022import javax.annotation.Nonnull; 023import static org.anarres.cpp.Token.CCOMMENT; 024import static org.anarres.cpp.Token.CPPCOMMENT; 025import static org.anarres.cpp.Token.EOF; 026 027/** 028 * A Reader wrapper around the Preprocessor. 029 * 030 * This is a utility class to provide a transparent {@link Reader} 031 * which preprocesses the input text. 032 * 033 * @see Preprocessor 034 * @see Reader 035 */ 036public class CppReader extends Reader implements Closeable { 037 038 private final Preprocessor cpp; 039 private String token; 040 private int idx; 041 042 public CppReader(@Nonnull final Reader r) { 043 cpp = new Preprocessor(new LexerSource(r, true) { 044 @Override 045 public String getName() { 046 return "<CppReader Input@" 047 + System.identityHashCode(r) + ">"; 048 } 049 }); 050 token = ""; 051 idx = 0; 052 } 053 054 public CppReader(@Nonnull Preprocessor p) { 055 cpp = p; 056 token = ""; 057 idx = 0; 058 } 059 060 /** 061 * Returns the Preprocessor used by this CppReader. 062 */ 063 @Nonnull 064 public Preprocessor getPreprocessor() { 065 return cpp; 066 } 067 068 /** 069 * Defines the given name as a macro. 070 * 071 * This is a convnience method. 072 */ 073 public void addMacro(@Nonnull String name) 074 throws LexerException { 075 cpp.addMacro(name); 076 } 077 078 /** 079 * Defines the given name as a macro. 080 * 081 * This is a convnience method. 082 */ 083 public void addMacro(@Nonnull String name, @Nonnull String value) 084 throws LexerException { 085 cpp.addMacro(name, value); 086 } 087 088 private boolean refill() 089 throws IOException { 090 try { 091 assert cpp != null : "cpp is null : was it closed?"; 092 if (token == null) 093 return false; 094 while (idx >= token.length()) { 095 Token tok = cpp.token(); 096 switch (tok.getType()) { 097 case EOF: 098 token = null; 099 return false; 100 case CCOMMENT: 101 case CPPCOMMENT: 102 if (!cpp.getFeature(Feature.KEEPCOMMENTS)) { 103 token = " "; 104 break; 105 } 106 default: 107 token = tok.getText(); 108 break; 109 } 110 idx = 0; 111 } 112 return true; 113 } catch (LexerException e) { 114 // new IOException(String, Throwable) is since 1.6 115 IOException _e = new IOException(String.valueOf(e)); 116 _e.initCause(e); 117 throw _e; 118 } 119 } 120 121 @Override 122 public int read() 123 throws IOException { 124 if (!refill()) 125 return -1; 126 return token.charAt(idx++); 127 } 128 129 @Override 130 /* XXX Very slow and inefficient. */ 131 public int read(char cbuf[], int off, int len) 132 throws IOException { 133 if (token == null) 134 return -1; 135 for (int i = 0; i < len; i++) { 136 int ch = read(); 137 if (ch == -1) 138 return i; 139 cbuf[off + i] = (char) ch; 140 } 141 return len; 142 } 143 144 @Override 145 public void close() 146 throws IOException { 147 cpp.close(); 148 token = null; 149 } 150 151}