001 /* 002 Copyright (C) 2001-2003 Laurent Martelli <laurent@aopsys.com> 003 004 This program is free software; you can redistribute it and/or modify 005 it under the terms of the GNU Lesser General Public License as 006 published by the Free Software Foundation; either version 2 of the 007 License, or (at your option) any later version. 008 009 This program is distributed in the hope that it will be useful, 010 but WITHOUT ANY WARRANTY; without even the implied warranty of 011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 GNU Lesser General Public License for more details. 013 014 You should have received a copy of the GNU Lesser General Public 015 License along with this program; if not, write to the Free Software 016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 017 USA */ 018 019 package org.objectweb.jac.core.parsers.acc; 020 021 022 import java.io.FileInputStream; 023 import java.io.FileNotFoundException; 024 import java.io.IOException; 025 import java.io.InputStream; 026 import java.io.InputStreamReader; 027 import java.io.Reader; 028 import java.io.StringWriter; 029 import java.net.MalformedURLException; 030 import java.net.URL; 031 import java.util.Set; 032 import java_cup.runtime.Scanner; 033 import java_cup.runtime.Symbol; 034 import org.apache.log4j.Logger; 035 import org.objectweb.jac.util.PushbackReader; 036 037 public class AccScanner implements Scanner { 038 static Logger logger = Logger.getLogger("acc.scanner"); 039 static Logger loggerParser = Logger.getLogger("acc.parser"); 040 041 PushbackReader input; 042 String streamName; 043 int line; 044 boolean bol; // beginning of line 045 boolean previousBol; // beginning of line 046 047 AccScanner include = null; 048 Set blockKeywords; 049 050 public AccScanner(Reader input, String streamName, Set blockKeywords) { 051 logger.debug("FileInputStream("+streamName+")"); 052 this.input = new PushbackReader(input,2); 053 this.streamName = streamName; 054 this.line = 1; 055 this.bol = true; 056 this.blockKeywords = blockKeywords; 057 //System.out.println(streamName+":INIT"); 058 } 059 060 public AccScanner(String streamName, Set blockKeywords) 061 throws IOException 062 { 063 InputStream inputStream = null; 064 try { 065 logger.debug("FileInputStream("+streamName+")"); 066 inputStream = new FileInputStream(streamName); 067 } catch ( FileNotFoundException e ) { 068 try { 069 logger.debug("getResourceAsStream("+streamName+")"); 070 inputStream = getClass().getClassLoader().getResourceAsStream(streamName); 071 } catch (Exception e2 ) { 072 logger.debug("new URL("+streamName+")"); 073 try { 074 URL url = new URL(streamName); 075 inputStream = url.openStream(); 076 } catch (MalformedURLException e3) { 077 e3.printStackTrace(); 078 } 079 } 080 } 081 082 if (inputStream==null) 083 throw new FileNotFoundException("file not found : "+streamName); 084 085 this.input = new PushbackReader(new InputStreamReader(inputStream),2); 086 this.streamName = streamName; 087 this.line = 1; 088 this.bol = true; 089 this.blockKeywords = blockKeywords; 090 091 // System.out.println(streamName+":INIT"); 092 } 093 094 public void printState() { 095 logger.error(getLine()); 096 if (include!=null) 097 include.printState(); 098 } 099 100 protected boolean isEof(int c) { 101 return c==-1 || c==65535; 102 } 103 104 public Symbol next_token() throws java.lang.Exception 105 { 106 if (include!=null) { 107 Symbol token = include.next_token(); 108 if (token.sym != -1) { 109 return token; 110 } 111 include = null; 112 } 113 114 boolean quoted = false; 115 int c = input.read(); 116 while (true) { 117 // skip white spaces and CR 118 while (c==' ' || c=='\t' || c=='\n' || c=='\r') { 119 //System.out.println(streamName+":"+line+":WHITESPACE"); 120 if (c=='\n' || c=='\r') { 121 //System.out.println(streamName+":"+line+":NEWLINE1"); 122 line++; 123 bol = true; 124 if (c=='\r') { 125 c = input.read(); 126 if (c != '\n') 127 input.unread(c); 128 } 129 } 130 c = input.read(); 131 } 132 // skip comments 133 if (c=='/') { 134 int ahead = input.read(); 135 if (ahead=='/') { 136 // c++-style comments 137 //System.out.println(streamName+":"+line+":C++ COMMENT"); 138 c = input.read(); 139 while (c!='\n' && c!='\r' && c!=-1) { 140 c = input.read(); 141 } 142 continue; 143 } if (ahead=='*') { 144 // c-style comments 145 //System.out.println(streamName+":"+line+":C COMMENT"); 146 int prev = c; 147 c = input.read(); 148 boolean state = false; 149 while (!(state && c=='/') && c!=-1) { 150 if ((c=='\n' && prev!='\r') || c=='\r') line++; 151 state = (c=='*'); 152 prev = c; 153 c = input.read(); 154 } 155 if (c==-1) { 156 logger.error("unclosed comment"); 157 printState(); 158 break; 159 } 160 c = input.read(); 161 continue; 162 163 } else { 164 input.unread(ahead); 165 break; 166 } 167 } 168 break; 169 } 170 171 int start = input.getPosition()-1; 172 Symbol token = null;/*new Symbol(AccSymbols.error);*/ 173 174 //System.out.println("Testing char `"+c+"' = `"+(char)c+"'"); 175 switch (c) { 176 case -1: 177 case 65535: 178 return null; 179 //token = new Symbol(AccSymbols.EOF); 180 //System.out.println(streamName+":TOKEN "+token.sym+"["+token.value+"]"); 181 //break; 182 case '{': 183 token = new Symbol(AccSymbols.LBRACE,start,start,"{"); 184 break; 185 case '}': 186 token = new Symbol(AccSymbols.RBRACE,start,start,"}"); 187 break; 188 case ',': 189 token = new Symbol(AccSymbols.COMMA,start,start,","); 190 break; 191 // when -1 is unread(), it becomes \uFFFF 192 case ';': 193 token = new Symbol(AccSymbols.EOL,start,start,";"); 194 break; 195 case '/': 196 token = new Symbol(AccSymbols.EOL,start,start,"/"); 197 break; 198 case '"': 199 // quoted string 200 { 201 quoted = true; 202 StringWriter value = new StringWriter(); 203 c = input.read(); 204 boolean escaped = false; 205 if (c=='\\') { 206 escaped = true; 207 c=readEscaped(input.read()); 208 } 209 while ((c!='"' || escaped) && !isEof(c)) { 210 value.write(c); 211 c = input.read(); 212 if (c=='\n') 213 line++; 214 escaped = false; 215 if (c=='\\') { 216 c=readEscaped(input.read()); 217 escaped = true; 218 } 219 } 220 //System.out.println("value="+value); 221 String str = value.toString(); 222 token = new Symbol(AccSymbols.ATOMIC_VALUE, 223 start,start+str.length()-1,str); 224 } 225 break; 226 default: 227 { 228 StringWriter value = new StringWriter(); 229 String delim="/{},; \t\n\r"; 230 while (delim.indexOf(c)==-1 && c!=-1) { 231 value.write(c); 232 c = input.read(); 233 } 234 input.unread(c); 235 //System.out.println("value="+value); 236 String str = value.toString(); 237 token = new Symbol(AccSymbols.ATOMIC_VALUE, 238 start,start+str.length()-1,str); 239 } 240 } 241 242 previousBol = bol; 243 244 if (bol && token.sym == AccSymbols.ATOMIC_VALUE && token.value.equals("include")) { 245 bol = false; 246 String filename = (String)next_token().value; 247 //System.out.println(streamName+":INCLUDE("+filename+")"); 248 include = new AccScanner(filename,blockKeywords); 249 return next_token(); 250 } 251 if (!quoted && token.sym == AccSymbols.ATOMIC_VALUE && 252 ( token.value.equals("class") || 253 token.value.equals("member") || 254 token.value.equals("method") || 255 token.value.equals("attribute") || 256 token.value.equals("block") || 257 blockKeywords.contains(token.value) ) ) 258 { 259 token.sym = AccSymbols.CLASS; 260 //System.out.println(streamName+":TOKEN block"); 261 } 262 if (!quoted && token.sym == AccSymbols.ATOMIC_VALUE && 263 token.value.equals("import")) { 264 token.sym = AccSymbols.IMPORT; 265 } 266 if (!quoted && token.sym == AccSymbols.ATOMIC_VALUE && 267 token.value.equals("null")) { 268 token.value = null; 269 } 270 token.left = start; 271 if (token.value instanceof String) 272 token.right = start + ((String)token.value).length() - 1; 273 if (quoted) 274 token.right += 2; 275 276 //System.out.println(streamName+":TOKEN "+token.sym+"["+token.value+"]"); 277 loggerParser.debug("read token "+token+" = "+token.value); 278 bol = false; 279 return token; 280 } 281 282 /** 283 * Read a char from input, possibly escaped by '\' 284 */ 285 int readEscaped(int c) throws IOException 286 { 287 switch (c) { 288 case 'n': 289 return '\n'; 290 case 'r': 291 return '\r'; 292 case 't': 293 return '\t'; 294 default: 295 return c; 296 } 297 } 298 299 /** 300 * Return the current line number 301 */ 302 public String getLine() { 303 if (include!=null) 304 return include.getLine(); 305 else 306 return streamName+":"+(previousBol?line-1:line); 307 } 308 309 }