/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2006 Silvano Rivoira * * All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License. See the file * * COPYRIGHT for more information. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* mjava language scanner specification */ import java_cup.runtime.*; %% %public %class Scanner %implements sym %unicode %line %column %cup %debug %{ StringBuffer string = new StringBuffer(); private Symbol symbol(int type) { return new Symbol(type, yyline+1, yycolumn+1); } private Symbol symbol(int type, Object value) { return new Symbol(type, yyline+1, yycolumn+1, value); } %} /* main character classes */ LineTerminator = \r|\n|\r\n InputCharacter = [^\r\n] WhiteSpace = {LineTerminator} | [ \t\f] /* comments */ Comment = {TraditionalComment} | {EndOfLineComment} | {DocumentationComment} TraditionalComment = "/*" [^*] ~"*/" | "/*" "*"+ "/" EndOfLineComment = "//" {InputCharacter}* {LineTerminator}? DocumentationComment = "/*" "*"+ [^/*] ~"*/" /* identifiers */ Identifier = [:jletter:][:jletterdigit:]* /* integer literals */ DecIntegerLiteral = 0 | [1-9][0-9]* /* floating point literals */ FloatLiteral = ({FLit1}|{FLit2}|{FLit3}) {Exponent}? FLit1 = [0-9]+ \. [0-9]* FLit2 = \. [0-9]+ FLit3 = [0-9]+ Exponent = [eE] [+-]? [0-9]+ /* string and character literals */ StringCharacter = [^\r\n\"\\] SingleCharacter = [^\r\n\'\\] %state STRING, CHARLITERAL %% { /* keywords */ "boolean" { return symbol(BOOLEAN); } "char" { return symbol(CHAR); } "class" { return symbol(CLASS); } "else" { return symbol(ELSE); } "extends" { return symbol(EXTENDS); } "float" { return symbol(FLOAT); } "int" { return symbol(INT); } "new" { return symbol(NEW); } "if" { return symbol(IF); } "public" { return symbol(PUBLIC); } "super" { return symbol(SUPER); } "return" { return symbol(RETURN); } "void" { return symbol(VOID); } "while" { return symbol(WHILE); } "this" { return symbol(THIS); } /* boolean literals */ "true" { return symbol(BOOLEAN_LITERAL, new Boolean(true)); } "false" { return symbol(BOOLEAN_LITERAL, new Boolean(false)); } /* null literal */ "null" { return symbol(NULL_LITERAL); } /* separators */ "(" { return symbol(LPAREN); } ")" { return symbol(RPAREN); } "{" { return symbol(LBRACE); } "}" { return symbol(RBRACE); } "[" { return symbol(LBRACK); } "]" { return symbol(RBRACK); } ";" { return symbol(SEMICOLON); } "," { return symbol(COMMA); } "." { return symbol(DOT); } /* operators */ "=" { return symbol(EQ); } ">" { return symbol(GT); } "<" { return symbol(LT); } "!" { return symbol(NOT); } "?" { return symbol(QUESTION); } ":" { return symbol(COLON); } "==" { return symbol(EQEQ); } "<=" { return symbol(LTEQ); } ">=" { return symbol(GTEQ); } "!=" { return symbol(NOTEQ); } "&&" { return symbol(ANDAND); } "&" { return symbol(AT); } "||" { return symbol(OROR); } "+" { return symbol(PLUS); } "-" { return symbol(MINUS); } "*" { return symbol(MULT); } "/" { return symbol(DIV); } "%" { return symbol(MOD); } /* string literal */ \" { yybegin(STRING); string.setLength(0); } /* character literal */ \' { yybegin(CHARLITERAL); } /* numeric literals */ {DecIntegerLiteral} { return symbol(INTEGER_LITERAL, new Integer(yytext())); } {FloatLiteral} { return symbol(FLOATING_POINT_LITERAL, new Float(yytext().substring(0,yylength()))); } /* comments */ {Comment} { /* ignore */ } /* whitespace */ {WhiteSpace} { /* ignore */ } /* identifiers */ {Identifier} { return symbol(IDENTIFIER, yytext()); } } { \" { yybegin(YYINITIAL); return symbol(STRING_LITERAL, string.toString()); } {StringCharacter}+ { string.append( yytext() ); } /* escape sequences */ "\\b" { string.append( '\b' ); } "\\t" { string.append( '\t' ); } "\\n" { string.append( '\n' ); } "\\f" { string.append( '\f' ); } "\\r" { string.append( '\r' ); } "\\\"" { string.append( '\"' ); } "\\'" { string.append( '\'' ); } "\\\\" { string.append( '\\' ); } /* error cases */ \\. { throw new RuntimeException("Illegal escape sequence \""+yytext()+"\""); } {LineTerminator} { throw new RuntimeException("Unterminated string at end of line"); } } { {SingleCharacter}\' { yybegin(YYINITIAL); return symbol(CHARACTER_LITERAL, new Character(yytext().charAt(0))); } /* escape sequences */ "\\b"\' { yybegin(YYINITIAL); return symbol(CHARACTER_LITERAL, new Character('\b'));} "\\t"\' { yybegin(YYINITIAL); return symbol(CHARACTER_LITERAL, new Character('\t'));} "\\n"\' { yybegin(YYINITIAL); return symbol(CHARACTER_LITERAL, new Character('\n'));} "\\f"\' { yybegin(YYINITIAL); return symbol(CHARACTER_LITERAL, new Character('\f'));} "\\r"\' { yybegin(YYINITIAL); return symbol(CHARACTER_LITERAL, new Character('\r'));} "\\\""\' { yybegin(YYINITIAL); return symbol(CHARACTER_LITERAL, new Character('\"'));} "\\'"\' { yybegin(YYINITIAL); return symbol(CHARACTER_LITERAL, new Character('\''));} "\\\\"\' { yybegin(YYINITIAL); return symbol(CHARACTER_LITERAL, new Character('\\')); } /* error cases */ {LineTerminator} { throw new RuntimeException("Unterminated character literal at end of line"); } } /* error fallback */ .|\n { return symbol(ILLEGAL_CHARACTER, yytext());} <> { return symbol(EOF); }