// Copyright 1996, Marimba Inc. All Rights Reserved.


// @(#)ScannerInputStream.java, 1.8, 06/10/96





package marimba.io;





import java.io.*;





/**


 * A scanner input stream. This is an efficient stream tokenizer for


 * integers, identifiers, strings, and special characters.


 *


 * @author	Arthur van Hoff


 * @version 	1.8, 06/10/96


 */


public


class ScannerInputStream extends FastInputStream {


    public final static int EOF 	= -1;


    public final static int INTEGER 	= -2;


    public final static int IDENTIFIER 	= -3;


    public final static int STRING 	= -4;





    public int tok;


    public int ln;





    public long intValue;


    public String strValue;





    int ch;


    private char buf[] = new char[32];





    public ScannerInputStream(String file) throws IOException {


	super(file);


	ln = 1;


	ch = read();


	scan();


    }





    public ScannerInputStream(File file) throws IOException {


	super(file);


	ln = 1;


	ch = read();


	scan();


    }





    public ScannerInputStream(InputStream in) {


	super(in);


	ln = 1;


	ch = read();


	scan();


    }





    public int scan() {


	int ch = this.ch;





        while (true) {


	    switch (ch) {


	      case ' ':


	      case '\t':


		ch = read();


		break;





	      case '\n':


		ln++;


		ch = read();


		break;





	      case '\r':


		ln++;


		if ((ch = read()) == '\n') {


		    ch  = read();


		}


		break;





	      case '#':


		ch = read();


		while ((ch != '\n') && (ch != '\r') && (ch != EOF)) {


		    ch = read();


		}


		break;





	      case EOF:


		return this.ch = tok = EOF;





	      case '"': {


		int n = 0;


		ch = read();


		while (ch != EOF) {


		    if (ch == '"') {


			ch = read();


			break;


		    }


		    if (n == buf.length) {


			char newbuf[] = new char[n * 2];


			System.arraycopy(buf, 0, newbuf, 0, n);


			buf = newbuf;


		    }


		    buf[n++] = (char)(ch & 0xFF);


		    switch (ch) {


		      case '\n':


			ln++;


			ch = read();


			break;





		      case '\r':


			ln++;


			buf[n - 1] = '\n';


			if ((ch = read()) == '\n') {


			    ch = read();


			}


			break;





		      case '\\':


			switch (ch = read()) {


			  case 'n': buf[n - 1] = '\n'; break;


			  case 't': buf[n - 1] = '\t'; break;


			  case 'f': buf[n - 1] = '\f'; break;


			  case 'r': buf[n - 1] = '\r'; break;


			  case '"': buf[n - 1] = '\"'; break;


			  case '\'': buf[n - 1] = '\''; break;


			  case '\\': buf[n - 1] = '\\'; break;


			}





		      default:


			ch = read();


			break;


		    }


		}


		strValue = new String(buf, 0, n);


		this.ch = ch;


		return tok = STRING;


	      }





	      default:


		if (ch == '-') {


		    ch = read();


		    if ((ch >= '0') && (ch <= '9')) {


			intValue = ch - '0';


			ch = read();


			while ((ch >= '0') && (ch <= '9')) {


			    intValue = intValue * 10 + ch - '0';


			    ch = read();


			}


			intValue = -intValue;


			this.ch = ch;


			return tok = INTEGER;


		    }


		    this.ch = ch;


		    return tok = '-';


		}


		if ((ch >= '0') && (ch <= '9')) {


		    intValue = ch - '0';


		    ch = read();


		    while ((ch >= '0') && (ch <= '9')) {


			intValue = intValue * 10 + ch - '0';


			ch = read();


		    }


		    this.ch = ch;


		    return tok = INTEGER;


		}





		if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) || (ch == '_')) {


		    int n = 1;


		    buf[0] = (char)ch;


		    ch = read();


		    while (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) || ((ch >= '0') && (ch <= '9')) || (ch == '_')) {


			if (n == buf.length) {


			    char newbuf[] = new char[n * 2];


			    System.arraycopy(buf, 0, newbuf, 0, n);


			    buf = newbuf;


			}


			buf[n++] = (char)ch;


			ch = read();


		    }


		    strValue = new String(buf, 0, n);


		    this.ch = ch;


		    return tok = IDENTIFIER;


		}


		this.ch = read();


		return tok = ch;


	    }


	}


    }





    public int scanHexByte() throws SyntaxError {


	int ch = this.ch;


	while ((ch == ' ') || (ch == '\t') || (ch == '\n') || (ch == '\r')) {


	    ch = read();


	}





	int n = 0;


	if ((ch >= '0') && (ch <= '9')) {


	    n = (ch - '0') << 4;


	} else if ((ch >= 'a') && (ch <= 'z')) {


	    n = (ch + 10 - 'a') << 4;


	} else if ((ch >= 'A') && (ch <= 'Z')) {


	    n = (ch + 10 - 'A') << 4;


	} else {


	    return -1;


	}


	ch = read();





	if ((ch >= '0') && (ch <= '9')) {


	    n |= ch - '0';


	} else if ((ch >= 'a') && (ch <= 'z')) {


	    n |= ch + 10 - 'a';


	} else if ((ch >= 'A') && (ch <= 'Z')) {


	    n |= ch + 10 - 'A';


	} else {


	    throw new SyntaxError("hex digit expected");


	}





	tok = this.ch = read();


	return n;


    }





    public void error(String str) throws SyntaxError {


	System.out.print((char)'"');


	System.out.print((char)ch);


	for (int i = 0 ; i < 20 ; i++) {


	    System.out.print((char)read());


	}


	System.out.println((char)'"');


	throw new SyntaxError(str);


    }





    public void expect(int expected) throws SyntaxError {


	if (tok != expected) {


	    if (expected >= 0) {


		error("expected: " + (char)expected);


	    } else {


		error("expected: " + expected);


	    }


	}


	scan();


    }





    public boolean next(int expected) {


	if (tok == expected) {


	    scan();


	    return true;


	}


	return false;


    }





    public static void main(String argv[]) {


	ScannerInputStream s = new ScannerInputStream(new FastInputStream(System.in));


	int t = s.scan();


	int n = 0;


	long tm = System.currentTimeMillis();


	while (t != EOF) {


	    n++;


	    t = s.scan();


	}


	tm = System.currentTimeMillis() - tm;


	System.out.println("done in " + tm + "ms");


	System.out.println("buf=" + s.buf.length);


	System.out.println("tokens=" + n);


	System.out.println("lines=" + (s.ln - 1));


    }


}


