|
|
|
@ -32,9 +32,10 @@ import java.util.ArrayList;
|
|
|
|
|
|
|
|
|
|
/** Producer of token-related values for the parser. */
|
|
|
|
|
final ComplexSymbolFactory symbolFactory = new ComplexSymbolFactory();
|
|
|
|
|
private int currIndent = 0;
|
|
|
|
|
private int currIndent = 0; //Current Indentation Level
|
|
|
|
|
private int currString = "";
|
|
|
|
|
private ArrayList<Integer> stack = new ArrayList<Integer>(20);
|
|
|
|
|
/*A stack that keeps track of the spaces in each Indentation Level*/
|
|
|
|
|
private ArrayList<Integer> stack = new ArrayList<Integer>(20);
|
|
|
|
|
/** Return a terminal symbol of syntactic category TYPE and no
|
|
|
|
|
* semantic value at the current source location. */
|
|
|
|
|
private Symbol symbol(int type) {
|
|
|
|
@ -57,7 +58,7 @@ import java.util.ArrayList;
|
|
|
|
|
return stack.remove(stack.size() - 1);
|
|
|
|
|
}
|
|
|
|
|
private int top(){
|
|
|
|
|
if(stack.isEmpty) return 0;
|
|
|
|
|
if(stack.isEmpty()) return 0;
|
|
|
|
|
return stack.get(stack.size() - 1);
|
|
|
|
|
}
|
|
|
|
|
%}
|
|
|
|
@ -67,39 +68,74 @@ import java.util.ArrayList;
|
|
|
|
|
WhiteSpace = [ \t]
|
|
|
|
|
LineBreak = \r|\n|\r\n
|
|
|
|
|
|
|
|
|
|
IntegerLiteral = 0|[1-9][0-9]*
|
|
|
|
|
StringLiteral = ([^\"\\]|(\\\")|(\\t)|(\\r)|(\\n)|(\\\\))*
|
|
|
|
|
Names = (_|[a-z]|[A-Z])(_|[a-z]|[A-Z])*
|
|
|
|
|
IntegerLiteral = 0|[1-9][0-9]* // Accroding to the manual, 00+ is illeagal
|
|
|
|
|
StringLiteral = ([^\"\\]|(\\\")|(\\t)|(\\r)|(\\n)|(\\\\))* // \n, \r, \t, \\, \" and Anything except \ and "
|
|
|
|
|
Identifiers = (_|[a-z]|[A-Z])(_|[a-z]|[A-Z][0-9])*
|
|
|
|
|
Comments = #[^\r\n]*
|
|
|
|
|
%%
|
|
|
|
|
|
|
|
|
|
<YYINITIAL>{
|
|
|
|
|
{WhiteSpace}
|
|
|
|
|
{
|
|
|
|
|
String space = yytext();
|
|
|
|
|
if(space == "\t")
|
|
|
|
|
currIndent += 8;
|
|
|
|
|
/*Add indentation */
|
|
|
|
|
if(yytext() == "\t")
|
|
|
|
|
currIndent += 8; //'\t' = 8 spaces
|
|
|
|
|
else
|
|
|
|
|
currIndent ++;
|
|
|
|
|
}
|
|
|
|
|
{LineBreak}
|
|
|
|
|
/*
|
|
|
|
|
# This python code will test if '\t' is 8 spaces
|
|
|
|
|
# It will run and print '1\n2'
|
|
|
|
|
# Please tell me if your Python reports an error
|
|
|
|
|
# Or you find documentations that says otherwise
|
|
|
|
|
|
|
|
|
|
if True:
|
|
|
|
|
print(1) # \t
|
|
|
|
|
print(2) # 8 spaces
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{LineBreak}
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
If this is a blank line, start over on the next line.
|
|
|
|
|
An empty line should just be ignored, therefore we don't
|
|
|
|
|
pass a NEWLINE to Cup.
|
|
|
|
|
*/
|
|
|
|
|
currIndent = 0;
|
|
|
|
|
}
|
|
|
|
|
{Comments} { /* ignored */ }
|
|
|
|
|
[^ \t\r\n#]
|
|
|
|
|
{Comments} { /* ignored */ } //Ignore blank lines
|
|
|
|
|
|
|
|
|
|
/*If it's not a blank line (Current character isn't a
|
|
|
|
|
Whitespace/linebreak/comment), deal with indentation here and
|
|
|
|
|
start accepting whatever is on this line in `AFTER' state*/
|
|
|
|
|
[^ \t\r\n#]
|
|
|
|
|
{
|
|
|
|
|
//rewind the current character.
|
|
|
|
|
yypushback(1);
|
|
|
|
|
if(top() > currIndent)
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
If the indentation of the line < indents current level should have,
|
|
|
|
|
keep dedenting until it reaches the right level.
|
|
|
|
|
It's like a loop, because we're not changing the state
|
|
|
|
|
and we rewinded the current character. So it will keep
|
|
|
|
|
going until top()<= currIndent and it will switch to
|
|
|
|
|
AFTER state.
|
|
|
|
|
*/
|
|
|
|
|
pop();
|
|
|
|
|
return symbol(ChocoPyTokens.DEDENT);
|
|
|
|
|
return symbol(ChocoPyTokens.DEDENT, currIndent);
|
|
|
|
|
}
|
|
|
|
|
/*Otherwise, we will start dealing with the rest
|
|
|
|
|
of the line after indentation in from the next token.*/
|
|
|
|
|
yystart(AFTER);
|
|
|
|
|
if(top()< currIndent)
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
If current indentation > indents current level should have,
|
|
|
|
|
start a new level which will have `currIndent' spaces.
|
|
|
|
|
*/
|
|
|
|
|
push(currIndent);
|
|
|
|
|
return symbol(ChocoPyTokens.INDENT);
|
|
|
|
|
return symbol(ChocoPyTokens.INDENT, currIndent);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -113,8 +149,7 @@ Comments = #[^\r\n]*
|
|
|
|
|
/* Literals. */
|
|
|
|
|
{IntegerLiteral} { return symbol(ChocoPyTokens.NUMBER,
|
|
|
|
|
Integer.parseInt(yytext())); }
|
|
|
|
|
// {StringLiteral} { return symbol(ChocoPyTokens.STRING, yytext());}
|
|
|
|
|
"\"" {yystart(STR); currString = "";}
|
|
|
|
|
"\"" {yystart(STR); currString = "";} //Start taking a string when see a "
|
|
|
|
|
"False" { return symbol(ChocoPyTokens.BOOL, false); }
|
|
|
|
|
"True" { return symbol(ChocoPyTokens.BOOL, true); }
|
|
|
|
|
"None" { return symbol(ChocoPyTokens.NONE); }
|
|
|
|
@ -154,7 +189,7 @@ Comments = #[^\r\n]*
|
|
|
|
|
"-" { return symbol(ChocoPyTokens.MINUS); }
|
|
|
|
|
"*" { return symbol(ChocoPyTokens.MUL); }
|
|
|
|
|
"//" { return symbol(ChocoPyTokens.DIV); }
|
|
|
|
|
"/" { return symbol(ChocoPyTokens.DIV); }
|
|
|
|
|
"/" { return symbol(ChocoPyTokens.DIV); } //Accroding to manual, chocopy don't have fp division, '/', '//' should be integr division
|
|
|
|
|
"%" { return symbol(ChocoPyTokens.MOD); }
|
|
|
|
|
">" { return symbol(ChocoPyTokens.GT); }
|
|
|
|
|
"<" { return symbol(ChocoPyTokens.LT); }
|
|
|
|
@ -176,16 +211,16 @@ Comments = #[^\r\n]*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*Identifiers*/
|
|
|
|
|
{Names} {return symbol(ChocoPyTokens.NAMES, yytext());}
|
|
|
|
|
{Identifiers} {return symbol(ChocoPyTokens.ID, yytext());}
|
|
|
|
|
/* Whitespace. */
|
|
|
|
|
{WhiteSpace} { /* ignore */ }
|
|
|
|
|
/* Comment. */
|
|
|
|
|
{Comments} { /* ignore */ }
|
|
|
|
|
}
|
|
|
|
|
<STR>{
|
|
|
|
|
{StringLiteral} {currString+=yytext();}
|
|
|
|
|
{StringLiteral} {currString += yytext();}
|
|
|
|
|
\\$ { /*'\' at the end of line, do nothing.*/ }
|
|
|
|
|
"\"" {yybegin(AFTER); return symbol(ChocoPyTokens.STRING, currString);}
|
|
|
|
|
"\"" {yybegin(AFTER); return symbol(ChocoPyTokens.STRING, currString);} // accepted a ", return to AFTER state
|
|
|
|
|
}
|
|
|
|
|
<<EOF>> { return symbol(ChocoPyTokens.EOF); }
|
|
|
|
|
|
|
|
|
|