Archived
Initial commit of version 2.1.
This commit is contained in:
@@ -0,0 +1,933 @@
|
||||
/*
|
||||
* @(#)Parser.java 2.1 2003/10/07
|
||||
*
|
||||
* Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown
|
||||
* Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland
|
||||
* and School of Computer and Math Sciences, The Robert Gordon University,
|
||||
* St. Andrew Street, Aberdeen AB25 1HG, Scotland.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is provided free for educational use only. It may
|
||||
* not be used for commercial purposes without the prior written permission
|
||||
* of the authors.
|
||||
*/
|
||||
|
||||
package Triangle.SyntacticAnalyzer;
|
||||
|
||||
import Triangle.ErrorReporter;
|
||||
import Triangle.AbstractSyntaxTrees.ActualParameter;
|
||||
import Triangle.AbstractSyntaxTrees.ActualParameterSequence;
|
||||
import Triangle.AbstractSyntaxTrees.ArrayAggregate;
|
||||
import Triangle.AbstractSyntaxTrees.ArrayExpression;
|
||||
import Triangle.AbstractSyntaxTrees.ArrayTypeDenoter;
|
||||
import Triangle.AbstractSyntaxTrees.AssignCommand;
|
||||
import Triangle.AbstractSyntaxTrees.BinaryExpression;
|
||||
import Triangle.AbstractSyntaxTrees.CallCommand;
|
||||
import Triangle.AbstractSyntaxTrees.CallExpression;
|
||||
import Triangle.AbstractSyntaxTrees.CharacterExpression;
|
||||
import Triangle.AbstractSyntaxTrees.CharacterLiteral;
|
||||
import Triangle.AbstractSyntaxTrees.Command;
|
||||
import Triangle.AbstractSyntaxTrees.ConstActualParameter;
|
||||
import Triangle.AbstractSyntaxTrees.ConstDeclaration;
|
||||
import Triangle.AbstractSyntaxTrees.ConstFormalParameter;
|
||||
import Triangle.AbstractSyntaxTrees.Declaration;
|
||||
import Triangle.AbstractSyntaxTrees.DotVname;
|
||||
import Triangle.AbstractSyntaxTrees.EmptyActualParameterSequence;
|
||||
import Triangle.AbstractSyntaxTrees.EmptyCommand;
|
||||
import Triangle.AbstractSyntaxTrees.EmptyFormalParameterSequence;
|
||||
import Triangle.AbstractSyntaxTrees.Expression;
|
||||
import Triangle.AbstractSyntaxTrees.FieldTypeDenoter;
|
||||
import Triangle.AbstractSyntaxTrees.FormalParameter;
|
||||
import Triangle.AbstractSyntaxTrees.FormalParameterSequence;
|
||||
import Triangle.AbstractSyntaxTrees.FuncActualParameter;
|
||||
import Triangle.AbstractSyntaxTrees.FuncDeclaration;
|
||||
import Triangle.AbstractSyntaxTrees.FuncFormalParameter;
|
||||
import Triangle.AbstractSyntaxTrees.Identifier;
|
||||
import Triangle.AbstractSyntaxTrees.IfCommand;
|
||||
import Triangle.AbstractSyntaxTrees.IfExpression;
|
||||
import Triangle.AbstractSyntaxTrees.IntegerExpression;
|
||||
import Triangle.AbstractSyntaxTrees.IntegerLiteral;
|
||||
import Triangle.AbstractSyntaxTrees.LetCommand;
|
||||
import Triangle.AbstractSyntaxTrees.LetExpression;
|
||||
import Triangle.AbstractSyntaxTrees.MultipleActualParameterSequence;
|
||||
import Triangle.AbstractSyntaxTrees.MultipleArrayAggregate;
|
||||
import Triangle.AbstractSyntaxTrees.MultipleFieldTypeDenoter;
|
||||
import Triangle.AbstractSyntaxTrees.MultipleFormalParameterSequence;
|
||||
import Triangle.AbstractSyntaxTrees.MultipleRecordAggregate;
|
||||
import Triangle.AbstractSyntaxTrees.Operator;
|
||||
import Triangle.AbstractSyntaxTrees.ProcActualParameter;
|
||||
import Triangle.AbstractSyntaxTrees.ProcDeclaration;
|
||||
import Triangle.AbstractSyntaxTrees.ProcFormalParameter;
|
||||
import Triangle.AbstractSyntaxTrees.Program;
|
||||
import Triangle.AbstractSyntaxTrees.RecordAggregate;
|
||||
import Triangle.AbstractSyntaxTrees.RecordExpression;
|
||||
import Triangle.AbstractSyntaxTrees.RecordTypeDenoter;
|
||||
import Triangle.AbstractSyntaxTrees.SequentialCommand;
|
||||
import Triangle.AbstractSyntaxTrees.SequentialDeclaration;
|
||||
import Triangle.AbstractSyntaxTrees.SimpleTypeDenoter;
|
||||
import Triangle.AbstractSyntaxTrees.SimpleVname;
|
||||
import Triangle.AbstractSyntaxTrees.SingleActualParameterSequence;
|
||||
import Triangle.AbstractSyntaxTrees.SingleArrayAggregate;
|
||||
import Triangle.AbstractSyntaxTrees.SingleFieldTypeDenoter;
|
||||
import Triangle.AbstractSyntaxTrees.SingleFormalParameterSequence;
|
||||
import Triangle.AbstractSyntaxTrees.SingleRecordAggregate;
|
||||
import Triangle.AbstractSyntaxTrees.SubscriptVname;
|
||||
import Triangle.AbstractSyntaxTrees.TypeDeclaration;
|
||||
import Triangle.AbstractSyntaxTrees.TypeDenoter;
|
||||
import Triangle.AbstractSyntaxTrees.UnaryExpression;
|
||||
import Triangle.AbstractSyntaxTrees.VarActualParameter;
|
||||
import Triangle.AbstractSyntaxTrees.VarDeclaration;
|
||||
import Triangle.AbstractSyntaxTrees.VarFormalParameter;
|
||||
import Triangle.AbstractSyntaxTrees.Vname;
|
||||
import Triangle.AbstractSyntaxTrees.VnameExpression;
|
||||
import Triangle.AbstractSyntaxTrees.WhileCommand;
|
||||
|
||||
public class Parser {
|
||||
|
||||
private Scanner lexicalAnalyser;
|
||||
private ErrorReporter errorReporter;
|
||||
private Token currentToken;
|
||||
private SourcePosition previousTokenPosition;
|
||||
|
||||
public Parser(Scanner lexer, ErrorReporter reporter) {
|
||||
lexicalAnalyser = lexer;
|
||||
errorReporter = reporter;
|
||||
previousTokenPosition = new SourcePosition();
|
||||
}
|
||||
|
||||
// accept checks whether the current token matches tokenExpected.
|
||||
// If so, fetches the next token.
|
||||
// If not, reports a syntactic error.
|
||||
|
||||
void accept(int tokenExpected) throws SyntaxError {
|
||||
if (currentToken.kind == tokenExpected) {
|
||||
previousTokenPosition = currentToken.position;
|
||||
currentToken = lexicalAnalyser.scan();
|
||||
} else {
|
||||
syntacticError("\"%\" expected here", Token.spell(tokenExpected));
|
||||
}
|
||||
}
|
||||
|
||||
void acceptIt() {
|
||||
previousTokenPosition = currentToken.position;
|
||||
currentToken = lexicalAnalyser.scan();
|
||||
}
|
||||
|
||||
// start records the position of the start of a phrase.
|
||||
// This is defined to be the position of the first
|
||||
// character of the first token of the phrase.
|
||||
|
||||
void start(SourcePosition position) {
|
||||
position.start = currentToken.position.start;
|
||||
}
|
||||
|
||||
// finish records the position of the end of a phrase.
|
||||
// This is defined to be the position of the last
|
||||
// character of the last token of the phrase.
|
||||
|
||||
void finish(SourcePosition position) {
|
||||
position.finish = previousTokenPosition.finish;
|
||||
}
|
||||
|
||||
void syntacticError(String messageTemplate, String tokenQuoted) throws SyntaxError {
|
||||
SourcePosition pos = currentToken.position;
|
||||
errorReporter.reportError(messageTemplate, tokenQuoted, pos);
|
||||
throw (new SyntaxError());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PROGRAMS
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public Program parseProgram() {
|
||||
|
||||
Program programAST = null;
|
||||
|
||||
previousTokenPosition.start = 0;
|
||||
previousTokenPosition.finish = 0;
|
||||
currentToken = lexicalAnalyser.scan();
|
||||
|
||||
try {
|
||||
Command cAST = parseCommand();
|
||||
programAST = new Program(cAST, previousTokenPosition);
|
||||
if (currentToken.kind != Token.EOT) {
|
||||
syntacticError("\"%\" not expected after end of program",
|
||||
currentToken.spelling);
|
||||
}
|
||||
} catch (SyntaxError s) {
|
||||
return null;
|
||||
}
|
||||
return programAST;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// LITERALS
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// parseIntegerLiteral parses an integer-literal, and constructs
|
||||
// a leaf AST to represent it.
|
||||
|
||||
IntegerLiteral parseIntegerLiteral() throws SyntaxError {
|
||||
IntegerLiteral IL = null;
|
||||
|
||||
if (currentToken.kind == Token.INTLITERAL) {
|
||||
previousTokenPosition = currentToken.position;
|
||||
String spelling = currentToken.spelling;
|
||||
IL = new IntegerLiteral(spelling, previousTokenPosition);
|
||||
currentToken = lexicalAnalyser.scan();
|
||||
} else {
|
||||
IL = null;
|
||||
syntacticError("integer literal expected here", "");
|
||||
}
|
||||
return IL;
|
||||
}
|
||||
|
||||
// parseCharacterLiteral parses a character-literal, and constructs a leaf
|
||||
// AST to represent it.
|
||||
|
||||
CharacterLiteral parseCharacterLiteral() throws SyntaxError {
|
||||
CharacterLiteral CL = null;
|
||||
|
||||
if (currentToken.kind == Token.CHARLITERAL) {
|
||||
previousTokenPosition = currentToken.position;
|
||||
String spelling = currentToken.spelling;
|
||||
CL = new CharacterLiteral(spelling, previousTokenPosition);
|
||||
currentToken = lexicalAnalyser.scan();
|
||||
} else {
|
||||
CL = null;
|
||||
syntacticError("character literal expected here", "");
|
||||
}
|
||||
return CL;
|
||||
}
|
||||
|
||||
// parseIdentifier parses an identifier, and constructs a leaf AST to
|
||||
// represent it.
|
||||
|
||||
Identifier parseIdentifier() throws SyntaxError {
|
||||
Identifier I = null;
|
||||
|
||||
if (currentToken.kind == Token.IDENTIFIER) {
|
||||
previousTokenPosition = currentToken.position;
|
||||
String spelling = currentToken.spelling;
|
||||
I = new Identifier(spelling, previousTokenPosition);
|
||||
currentToken = lexicalAnalyser.scan();
|
||||
} else {
|
||||
I = null;
|
||||
syntacticError("identifier expected here", "");
|
||||
}
|
||||
return I;
|
||||
}
|
||||
|
||||
// parseOperator parses an operator, and constructs a leaf AST to
|
||||
// represent it.
|
||||
|
||||
Operator parseOperator() throws SyntaxError {
|
||||
Operator O = null;
|
||||
|
||||
if (currentToken.kind == Token.OPERATOR) {
|
||||
previousTokenPosition = currentToken.position;
|
||||
String spelling = currentToken.spelling;
|
||||
O = new Operator(spelling, previousTokenPosition);
|
||||
currentToken = lexicalAnalyser.scan();
|
||||
} else {
|
||||
O = null;
|
||||
syntacticError("operator expected here", "");
|
||||
}
|
||||
return O;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// COMMANDS
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// parseCommand parses the command, and constructs an AST
|
||||
// to represent its phrase structure.
|
||||
|
||||
Command parseCommand() throws SyntaxError {
|
||||
Command commandAST = null; // in case there's a syntactic error
|
||||
|
||||
SourcePosition commandPos = new SourcePosition();
|
||||
|
||||
start(commandPos);
|
||||
commandAST = parseSingleCommand();
|
||||
while (currentToken.kind == Token.SEMICOLON) {
|
||||
acceptIt();
|
||||
Command c2AST = parseSingleCommand();
|
||||
finish(commandPos);
|
||||
commandAST = new SequentialCommand(commandAST, c2AST, commandPos);
|
||||
}
|
||||
return commandAST;
|
||||
}
|
||||
|
||||
Command parseSingleCommand() throws SyntaxError {
|
||||
Command commandAST = null; // in case there's a syntactic error
|
||||
|
||||
SourcePosition commandPos = new SourcePosition();
|
||||
start(commandPos);
|
||||
|
||||
switch (currentToken.kind) {
|
||||
|
||||
case Token.IDENTIFIER: {
|
||||
Identifier iAST = parseIdentifier();
|
||||
if (currentToken.kind == Token.LPAREN) {
|
||||
acceptIt();
|
||||
ActualParameterSequence apsAST = parseActualParameterSequence();
|
||||
accept(Token.RPAREN);
|
||||
finish(commandPos);
|
||||
commandAST = new CallCommand(iAST, apsAST, commandPos);
|
||||
|
||||
} else {
|
||||
|
||||
Vname vAST = parseRestOfVname(iAST);
|
||||
accept(Token.BECOMES);
|
||||
Expression eAST = parseExpression();
|
||||
finish(commandPos);
|
||||
commandAST = new AssignCommand(vAST, eAST, commandPos);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.BEGIN:
|
||||
acceptIt();
|
||||
commandAST = parseCommand();
|
||||
accept(Token.END);
|
||||
break;
|
||||
|
||||
case Token.LET: {
|
||||
acceptIt();
|
||||
Declaration dAST = parseDeclaration();
|
||||
accept(Token.IN);
|
||||
Command cAST = parseSingleCommand();
|
||||
finish(commandPos);
|
||||
commandAST = new LetCommand(dAST, cAST, commandPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.IF: {
|
||||
acceptIt();
|
||||
Expression eAST = parseExpression();
|
||||
accept(Token.THEN);
|
||||
Command c1AST = parseSingleCommand();
|
||||
accept(Token.ELSE);
|
||||
Command c2AST = parseSingleCommand();
|
||||
finish(commandPos);
|
||||
commandAST = new IfCommand(eAST, c1AST, c2AST, commandPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.WHILE: {
|
||||
acceptIt();
|
||||
Expression eAST = parseExpression();
|
||||
accept(Token.DO);
|
||||
Command cAST = parseSingleCommand();
|
||||
finish(commandPos);
|
||||
commandAST = new WhileCommand(eAST, cAST, commandPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.SEMICOLON:
|
||||
case Token.END:
|
||||
case Token.ELSE:
|
||||
case Token.IN:
|
||||
case Token.EOT:
|
||||
|
||||
finish(commandPos);
|
||||
commandAST = new EmptyCommand(commandPos);
|
||||
break;
|
||||
|
||||
default:
|
||||
syntacticError("\"%\" cannot start a command",
|
||||
currentToken.spelling);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return commandAST;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// EXPRESSIONS
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Expression parseExpression() throws SyntaxError {
|
||||
Expression expressionAST = null; // in case there's a syntactic error
|
||||
|
||||
SourcePosition expressionPos = new SourcePosition();
|
||||
|
||||
start(expressionPos);
|
||||
|
||||
switch (currentToken.kind) {
|
||||
|
||||
case Token.LET: {
|
||||
acceptIt();
|
||||
Declaration dAST = parseDeclaration();
|
||||
accept(Token.IN);
|
||||
Expression eAST = parseExpression();
|
||||
finish(expressionPos);
|
||||
expressionAST = new LetExpression(dAST, eAST, expressionPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.IF: {
|
||||
acceptIt();
|
||||
Expression e1AST = parseExpression();
|
||||
accept(Token.THEN);
|
||||
Expression e2AST = parseExpression();
|
||||
accept(Token.ELSE);
|
||||
Expression e3AST = parseExpression();
|
||||
finish(expressionPos);
|
||||
expressionAST = new IfExpression(e1AST, e2AST, e3AST, expressionPos);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
expressionAST = parseSecondaryExpression();
|
||||
break;
|
||||
}
|
||||
return expressionAST;
|
||||
}
|
||||
|
||||
Expression parseSecondaryExpression() throws SyntaxError {
|
||||
Expression expressionAST = null; // in case there's a syntactic error
|
||||
|
||||
SourcePosition expressionPos = new SourcePosition();
|
||||
start(expressionPos);
|
||||
|
||||
expressionAST = parsePrimaryExpression();
|
||||
while (currentToken.kind == Token.OPERATOR) {
|
||||
Operator opAST = parseOperator();
|
||||
Expression e2AST = parsePrimaryExpression();
|
||||
expressionAST = new BinaryExpression(expressionAST, opAST, e2AST,
|
||||
expressionPos);
|
||||
}
|
||||
return expressionAST;
|
||||
}
|
||||
|
||||
Expression parsePrimaryExpression() throws SyntaxError {
|
||||
Expression expressionAST = null; // in case there's a syntactic error
|
||||
|
||||
SourcePosition expressionPos = new SourcePosition();
|
||||
start(expressionPos);
|
||||
|
||||
switch (currentToken.kind) {
|
||||
|
||||
case Token.INTLITERAL: {
|
||||
IntegerLiteral ilAST = parseIntegerLiteral();
|
||||
finish(expressionPos);
|
||||
expressionAST = new IntegerExpression(ilAST, expressionPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.CHARLITERAL: {
|
||||
CharacterLiteral clAST = parseCharacterLiteral();
|
||||
finish(expressionPos);
|
||||
expressionAST = new CharacterExpression(clAST, expressionPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.LBRACKET: {
|
||||
acceptIt();
|
||||
ArrayAggregate aaAST = parseArrayAggregate();
|
||||
accept(Token.RBRACKET);
|
||||
finish(expressionPos);
|
||||
expressionAST = new ArrayExpression(aaAST, expressionPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.LCURLY: {
|
||||
acceptIt();
|
||||
RecordAggregate raAST = parseRecordAggregate();
|
||||
accept(Token.RCURLY);
|
||||
finish(expressionPos);
|
||||
expressionAST = new RecordExpression(raAST, expressionPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.IDENTIFIER: {
|
||||
Identifier iAST = parseIdentifier();
|
||||
if (currentToken.kind == Token.LPAREN) {
|
||||
acceptIt();
|
||||
ActualParameterSequence apsAST = parseActualParameterSequence();
|
||||
accept(Token.RPAREN);
|
||||
finish(expressionPos);
|
||||
expressionAST = new CallExpression(iAST, apsAST, expressionPos);
|
||||
|
||||
} else {
|
||||
Vname vAST = parseRestOfVname(iAST);
|
||||
finish(expressionPos);
|
||||
expressionAST = new VnameExpression(vAST, expressionPos);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.OPERATOR: {
|
||||
Operator opAST = parseOperator();
|
||||
Expression eAST = parsePrimaryExpression();
|
||||
finish(expressionPos);
|
||||
expressionAST = new UnaryExpression(opAST, eAST, expressionPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.LPAREN:
|
||||
acceptIt();
|
||||
expressionAST = parseExpression();
|
||||
accept(Token.RPAREN);
|
||||
break;
|
||||
|
||||
default:
|
||||
syntacticError("\"%\" cannot start an expression",
|
||||
currentToken.spelling);
|
||||
break;
|
||||
|
||||
}
|
||||
return expressionAST;
|
||||
}
|
||||
|
||||
RecordAggregate parseRecordAggregate() throws SyntaxError {
|
||||
RecordAggregate aggregateAST = null; // in case there's a syntactic error
|
||||
|
||||
SourcePosition aggregatePos = new SourcePosition();
|
||||
start(aggregatePos);
|
||||
|
||||
Identifier iAST = parseIdentifier();
|
||||
accept(Token.IS);
|
||||
Expression eAST = parseExpression();
|
||||
|
||||
if (currentToken.kind == Token.COMMA) {
|
||||
acceptIt();
|
||||
RecordAggregate aAST = parseRecordAggregate();
|
||||
finish(aggregatePos);
|
||||
aggregateAST = new MultipleRecordAggregate(iAST, eAST, aAST, aggregatePos);
|
||||
} else {
|
||||
finish(aggregatePos);
|
||||
aggregateAST = new SingleRecordAggregate(iAST, eAST, aggregatePos);
|
||||
}
|
||||
return aggregateAST;
|
||||
}
|
||||
|
||||
ArrayAggregate parseArrayAggregate() throws SyntaxError {
|
||||
ArrayAggregate aggregateAST = null; // in case there's a syntactic error
|
||||
|
||||
SourcePosition aggregatePos = new SourcePosition();
|
||||
start(aggregatePos);
|
||||
|
||||
Expression eAST = parseExpression();
|
||||
if (currentToken.kind == Token.COMMA) {
|
||||
acceptIt();
|
||||
ArrayAggregate aAST = parseArrayAggregate();
|
||||
finish(aggregatePos);
|
||||
aggregateAST = new MultipleArrayAggregate(eAST, aAST, aggregatePos);
|
||||
} else {
|
||||
finish(aggregatePos);
|
||||
aggregateAST = new SingleArrayAggregate(eAST, aggregatePos);
|
||||
}
|
||||
return aggregateAST;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// VALUE-OR-VARIABLE NAMES
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Vname parseVname() throws SyntaxError {
|
||||
Vname vnameAST = null; // in case there's a syntactic error
|
||||
Identifier iAST = parseIdentifier();
|
||||
vnameAST = parseRestOfVname(iAST);
|
||||
return vnameAST;
|
||||
}
|
||||
|
||||
Vname parseRestOfVname(Identifier identifierAST) throws SyntaxError {
|
||||
SourcePosition vnamePos = new SourcePosition();
|
||||
vnamePos = identifierAST.position;
|
||||
Vname vAST = new SimpleVname(identifierAST, vnamePos);
|
||||
|
||||
while (currentToken.kind == Token.DOT ||
|
||||
currentToken.kind == Token.LBRACKET) {
|
||||
|
||||
if (currentToken.kind == Token.DOT) {
|
||||
acceptIt();
|
||||
Identifier iAST = parseIdentifier();
|
||||
vAST = new DotVname(vAST, iAST, vnamePos);
|
||||
} else {
|
||||
acceptIt();
|
||||
Expression eAST = parseExpression();
|
||||
accept(Token.RBRACKET);
|
||||
finish(vnamePos);
|
||||
vAST = new SubscriptVname(vAST, eAST, vnamePos);
|
||||
}
|
||||
}
|
||||
return vAST;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DECLARATIONS
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Declaration parseDeclaration() throws SyntaxError {
|
||||
Declaration declarationAST = null; // in case there's a syntactic error
|
||||
|
||||
SourcePosition declarationPos = new SourcePosition();
|
||||
start(declarationPos);
|
||||
declarationAST = parseSingleDeclaration();
|
||||
while (currentToken.kind == Token.SEMICOLON) {
|
||||
acceptIt();
|
||||
Declaration d2AST = parseSingleDeclaration();
|
||||
finish(declarationPos);
|
||||
declarationAST = new SequentialDeclaration(declarationAST, d2AST,
|
||||
declarationPos);
|
||||
}
|
||||
return declarationAST;
|
||||
}
|
||||
|
||||
Declaration parseSingleDeclaration() throws SyntaxError {
|
||||
Declaration declarationAST = null; // in case there's a syntactic error
|
||||
|
||||
SourcePosition declarationPos = new SourcePosition();
|
||||
start(declarationPos);
|
||||
|
||||
switch (currentToken.kind) {
|
||||
|
||||
case Token.CONST: {
|
||||
acceptIt();
|
||||
Identifier iAST = parseIdentifier();
|
||||
accept(Token.IS);
|
||||
Expression eAST = parseExpression();
|
||||
finish(declarationPos);
|
||||
declarationAST = new ConstDeclaration(iAST, eAST, declarationPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.VAR: {
|
||||
acceptIt();
|
||||
Identifier iAST = parseIdentifier();
|
||||
accept(Token.COLON);
|
||||
TypeDenoter tAST = parseTypeDenoter();
|
||||
finish(declarationPos);
|
||||
declarationAST = new VarDeclaration(iAST, tAST, declarationPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.PROC: {
|
||||
acceptIt();
|
||||
Identifier iAST = parseIdentifier();
|
||||
accept(Token.LPAREN);
|
||||
FormalParameterSequence fpsAST = parseFormalParameterSequence();
|
||||
accept(Token.RPAREN);
|
||||
accept(Token.IS);
|
||||
Command cAST = parseSingleCommand();
|
||||
finish(declarationPos);
|
||||
declarationAST = new ProcDeclaration(iAST, fpsAST, cAST, declarationPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.FUNC: {
|
||||
acceptIt();
|
||||
Identifier iAST = parseIdentifier();
|
||||
accept(Token.LPAREN);
|
||||
FormalParameterSequence fpsAST = parseFormalParameterSequence();
|
||||
accept(Token.RPAREN);
|
||||
accept(Token.COLON);
|
||||
TypeDenoter tAST = parseTypeDenoter();
|
||||
accept(Token.IS);
|
||||
Expression eAST = parseExpression();
|
||||
finish(declarationPos);
|
||||
declarationAST = new FuncDeclaration(iAST, fpsAST, tAST, eAST,
|
||||
declarationPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.TYPE: {
|
||||
acceptIt();
|
||||
Identifier iAST = parseIdentifier();
|
||||
accept(Token.IS);
|
||||
TypeDenoter tAST = parseTypeDenoter();
|
||||
finish(declarationPos);
|
||||
declarationAST = new TypeDeclaration(iAST, tAST, declarationPos);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
syntacticError("\"%\" cannot start a declaration",
|
||||
currentToken.spelling);
|
||||
break;
|
||||
|
||||
}
|
||||
return declarationAST;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PARAMETERS
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FormalParameterSequence parseFormalParameterSequence() throws SyntaxError {
|
||||
FormalParameterSequence formalsAST;
|
||||
|
||||
SourcePosition formalsPos = new SourcePosition();
|
||||
|
||||
start(formalsPos);
|
||||
if (currentToken.kind == Token.RPAREN) {
|
||||
finish(formalsPos);
|
||||
formalsAST = new EmptyFormalParameterSequence(formalsPos);
|
||||
|
||||
} else {
|
||||
formalsAST = parseProperFormalParameterSequence();
|
||||
}
|
||||
return formalsAST;
|
||||
}
|
||||
|
||||
FormalParameterSequence parseProperFormalParameterSequence() throws SyntaxError {
|
||||
FormalParameterSequence formalsAST = null; // in case there's a syntactic error;
|
||||
|
||||
SourcePosition formalsPos = new SourcePosition();
|
||||
start(formalsPos);
|
||||
FormalParameter fpAST = parseFormalParameter();
|
||||
if (currentToken.kind == Token.COMMA) {
|
||||
acceptIt();
|
||||
FormalParameterSequence fpsAST = parseProperFormalParameterSequence();
|
||||
finish(formalsPos);
|
||||
formalsAST = new MultipleFormalParameterSequence(fpAST, fpsAST,
|
||||
formalsPos);
|
||||
|
||||
} else {
|
||||
finish(formalsPos);
|
||||
formalsAST = new SingleFormalParameterSequence(fpAST, formalsPos);
|
||||
}
|
||||
return formalsAST;
|
||||
}
|
||||
|
||||
FormalParameter parseFormalParameter() throws SyntaxError {
|
||||
FormalParameter formalAST = null; // in case there's a syntactic error;
|
||||
|
||||
SourcePosition formalPos = new SourcePosition();
|
||||
start(formalPos);
|
||||
|
||||
switch (currentToken.kind) {
|
||||
|
||||
case Token.IDENTIFIER: {
|
||||
Identifier iAST = parseIdentifier();
|
||||
accept(Token.COLON);
|
||||
TypeDenoter tAST = parseTypeDenoter();
|
||||
finish(formalPos);
|
||||
formalAST = new ConstFormalParameter(iAST, tAST, formalPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.VAR: {
|
||||
acceptIt();
|
||||
Identifier iAST = parseIdentifier();
|
||||
accept(Token.COLON);
|
||||
TypeDenoter tAST = parseTypeDenoter();
|
||||
finish(formalPos);
|
||||
formalAST = new VarFormalParameter(iAST, tAST, formalPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.PROC: {
|
||||
acceptIt();
|
||||
Identifier iAST = parseIdentifier();
|
||||
accept(Token.LPAREN);
|
||||
FormalParameterSequence fpsAST = parseFormalParameterSequence();
|
||||
accept(Token.RPAREN);
|
||||
finish(formalPos);
|
||||
formalAST = new ProcFormalParameter(iAST, fpsAST, formalPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.FUNC: {
|
||||
acceptIt();
|
||||
Identifier iAST = parseIdentifier();
|
||||
accept(Token.LPAREN);
|
||||
FormalParameterSequence fpsAST = parseFormalParameterSequence();
|
||||
accept(Token.RPAREN);
|
||||
accept(Token.COLON);
|
||||
TypeDenoter tAST = parseTypeDenoter();
|
||||
finish(formalPos);
|
||||
formalAST = new FuncFormalParameter(iAST, fpsAST, tAST, formalPos);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
syntacticError("\"%\" cannot start a formal parameter",
|
||||
currentToken.spelling);
|
||||
break;
|
||||
|
||||
}
|
||||
return formalAST;
|
||||
}
|
||||
|
||||
ActualParameterSequence parseActualParameterSequence() throws SyntaxError {
|
||||
ActualParameterSequence actualsAST;
|
||||
|
||||
SourcePosition actualsPos = new SourcePosition();
|
||||
|
||||
start(actualsPos);
|
||||
if (currentToken.kind == Token.RPAREN) {
|
||||
finish(actualsPos);
|
||||
actualsAST = new EmptyActualParameterSequence(actualsPos);
|
||||
|
||||
} else {
|
||||
actualsAST = parseProperActualParameterSequence();
|
||||
}
|
||||
return actualsAST;
|
||||
}
|
||||
|
||||
ActualParameterSequence parseProperActualParameterSequence() throws SyntaxError {
|
||||
ActualParameterSequence actualsAST = null; // in case there's a syntactic error
|
||||
|
||||
SourcePosition actualsPos = new SourcePosition();
|
||||
|
||||
start(actualsPos);
|
||||
ActualParameter apAST = parseActualParameter();
|
||||
if (currentToken.kind == Token.COMMA) {
|
||||
acceptIt();
|
||||
ActualParameterSequence apsAST = parseProperActualParameterSequence();
|
||||
finish(actualsPos);
|
||||
actualsAST = new MultipleActualParameterSequence(apAST, apsAST,
|
||||
actualsPos);
|
||||
} else {
|
||||
finish(actualsPos);
|
||||
actualsAST = new SingleActualParameterSequence(apAST, actualsPos);
|
||||
}
|
||||
return actualsAST;
|
||||
}
|
||||
|
||||
ActualParameter parseActualParameter() throws SyntaxError {
|
||||
ActualParameter actualAST = null; // in case there's a syntactic error
|
||||
|
||||
SourcePosition actualPos = new SourcePosition();
|
||||
|
||||
start(actualPos);
|
||||
|
||||
switch (currentToken.kind) {
|
||||
|
||||
case Token.IDENTIFIER:
|
||||
case Token.INTLITERAL:
|
||||
case Token.CHARLITERAL:
|
||||
case Token.OPERATOR:
|
||||
case Token.LET:
|
||||
case Token.IF:
|
||||
case Token.LPAREN:
|
||||
case Token.LBRACKET:
|
||||
case Token.LCURLY: {
|
||||
Expression eAST = parseExpression();
|
||||
finish(actualPos);
|
||||
actualAST = new ConstActualParameter(eAST, actualPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.VAR: {
|
||||
acceptIt();
|
||||
Vname vAST = parseVname();
|
||||
finish(actualPos);
|
||||
actualAST = new VarActualParameter(vAST, actualPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.PROC: {
|
||||
acceptIt();
|
||||
Identifier iAST = parseIdentifier();
|
||||
finish(actualPos);
|
||||
actualAST = new ProcActualParameter(iAST, actualPos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.FUNC: {
|
||||
acceptIt();
|
||||
Identifier iAST = parseIdentifier();
|
||||
finish(actualPos);
|
||||
actualAST = new FuncActualParameter(iAST, actualPos);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
syntacticError("\"%\" cannot start an actual parameter",
|
||||
currentToken.spelling);
|
||||
break;
|
||||
|
||||
}
|
||||
return actualAST;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TYPE-DENOTERS
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TypeDenoter parseTypeDenoter() throws SyntaxError {
|
||||
TypeDenoter typeAST = null; // in case there's a syntactic error
|
||||
SourcePosition typePos = new SourcePosition();
|
||||
|
||||
start(typePos);
|
||||
|
||||
switch (currentToken.kind) {
|
||||
|
||||
case Token.IDENTIFIER: {
|
||||
Identifier iAST = parseIdentifier();
|
||||
finish(typePos);
|
||||
typeAST = new SimpleTypeDenoter(iAST, typePos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.ARRAY: {
|
||||
acceptIt();
|
||||
IntegerLiteral ilAST = parseIntegerLiteral();
|
||||
accept(Token.OF);
|
||||
TypeDenoter tAST = parseTypeDenoter();
|
||||
finish(typePos);
|
||||
typeAST = new ArrayTypeDenoter(ilAST, tAST, typePos);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.RECORD: {
|
||||
acceptIt();
|
||||
FieldTypeDenoter fAST = parseFieldTypeDenoter();
|
||||
accept(Token.END);
|
||||
finish(typePos);
|
||||
typeAST = new RecordTypeDenoter(fAST, typePos);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
syntacticError("\"%\" cannot start a type denoter",
|
||||
currentToken.spelling);
|
||||
break;
|
||||
|
||||
}
|
||||
return typeAST;
|
||||
}
|
||||
|
||||
FieldTypeDenoter parseFieldTypeDenoter() throws SyntaxError {
|
||||
FieldTypeDenoter fieldAST = null; // in case there's a syntactic error
|
||||
|
||||
SourcePosition fieldPos = new SourcePosition();
|
||||
|
||||
start(fieldPos);
|
||||
Identifier iAST = parseIdentifier();
|
||||
accept(Token.COLON);
|
||||
TypeDenoter tAST = parseTypeDenoter();
|
||||
if (currentToken.kind == Token.COMMA) {
|
||||
acceptIt();
|
||||
FieldTypeDenoter fAST = parseFieldTypeDenoter();
|
||||
finish(fieldPos);
|
||||
fieldAST = new MultipleFieldTypeDenoter(iAST, tAST, fAST, fieldPos);
|
||||
} else {
|
||||
finish(fieldPos);
|
||||
fieldAST = new SingleFieldTypeDenoter(iAST, tAST, fieldPos);
|
||||
}
|
||||
return fieldAST;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* @(#)Scanner.java 2.1 2003/10/07
|
||||
*
|
||||
* Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown
|
||||
* Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland
|
||||
* and School of Computer and Math Sciences, The Robert Gordon University,
|
||||
* St. Andrew Street, Aberdeen AB25 1HG, Scotland.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is provided free for educational use only. It may
|
||||
* not be used for commercial purposes without the prior written permission
|
||||
* of the authors.
|
||||
*/
|
||||
|
||||
package Triangle.SyntacticAnalyzer;
|
||||
|
||||
public final class Scanner {
|
||||
|
||||
private SourceFile sourceFile;
|
||||
private boolean debug;
|
||||
|
||||
private char currentChar;
|
||||
private StringBuffer currentSpelling;
|
||||
private boolean currentlyScanningToken;
|
||||
|
||||
private boolean isLetter(char c) {
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||
}
|
||||
|
||||
private boolean isDigit(char c) {
|
||||
return (c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
// isOperator returns true iff the given character is an operator character.
|
||||
|
||||
private boolean isOperator(char c) {
|
||||
return (c == '+' || c == '-' || c == '*' || c == '/' ||
|
||||
c == '=' || c == '<' || c == '>' || c == '\\' ||
|
||||
c == '&' || c == '@' || c == '%' || c == '^' ||
|
||||
c == '?');
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public Scanner(SourceFile source) {
|
||||
sourceFile = source;
|
||||
currentChar = sourceFile.getSource();
|
||||
debug = false;
|
||||
}
|
||||
|
||||
public void enableDebugging() {
|
||||
debug = true;
|
||||
}
|
||||
|
||||
// takeIt appends the current character to the current token, and gets
|
||||
// the next character from the source program.
|
||||
|
||||
private void takeIt() {
|
||||
if (currentlyScanningToken)
|
||||
currentSpelling.append(currentChar);
|
||||
currentChar = sourceFile.getSource();
|
||||
}
|
||||
|
||||
// scanSeparator skips a single separator.
|
||||
|
||||
private void scanSeparator() {
|
||||
switch (currentChar) {
|
||||
case '!': {
|
||||
takeIt();
|
||||
while ((currentChar != SourceFile.EOL) && (currentChar != SourceFile.EOT))
|
||||
takeIt();
|
||||
if (currentChar == SourceFile.EOL)
|
||||
takeIt();
|
||||
}
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
takeIt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private int scanToken() {
|
||||
|
||||
switch (currentChar) {
|
||||
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'h':
|
||||
case 'i':
|
||||
case 'j':
|
||||
case 'k':
|
||||
case 'l':
|
||||
case 'm':
|
||||
case 'n':
|
||||
case 'o':
|
||||
case 'p':
|
||||
case 'q':
|
||||
case 'r':
|
||||
case 's':
|
||||
case 't':
|
||||
case 'u':
|
||||
case 'v':
|
||||
case 'w':
|
||||
case 'x':
|
||||
case 'y':
|
||||
case 'z':
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
case 'G':
|
||||
case 'H':
|
||||
case 'I':
|
||||
case 'J':
|
||||
case 'K':
|
||||
case 'L':
|
||||
case 'M':
|
||||
case 'N':
|
||||
case 'O':
|
||||
case 'P':
|
||||
case 'Q':
|
||||
case 'R':
|
||||
case 'S':
|
||||
case 'T':
|
||||
case 'U':
|
||||
case 'V':
|
||||
case 'W':
|
||||
case 'X':
|
||||
case 'Y':
|
||||
case 'Z':
|
||||
takeIt();
|
||||
while (isLetter(currentChar) || isDigit(currentChar))
|
||||
takeIt();
|
||||
return Token.IDENTIFIER;
|
||||
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
takeIt();
|
||||
while (isDigit(currentChar))
|
||||
takeIt();
|
||||
return Token.INTLITERAL;
|
||||
|
||||
case '+':
|
||||
case '-':
|
||||
case '*':
|
||||
case '/':
|
||||
case '=':
|
||||
case '<':
|
||||
case '>':
|
||||
case '\\':
|
||||
case '&':
|
||||
case '@':
|
||||
case '%':
|
||||
case '^':
|
||||
case '?':
|
||||
takeIt();
|
||||
while (isOperator(currentChar))
|
||||
takeIt();
|
||||
return Token.OPERATOR;
|
||||
|
||||
case '\'':
|
||||
takeIt();
|
||||
takeIt(); // the quoted character
|
||||
if (currentChar == '\'') {
|
||||
takeIt();
|
||||
return Token.CHARLITERAL;
|
||||
} else
|
||||
return Token.ERROR;
|
||||
|
||||
case '.':
|
||||
takeIt();
|
||||
return Token.DOT;
|
||||
|
||||
case ':':
|
||||
takeIt();
|
||||
if (currentChar == '=') {
|
||||
takeIt();
|
||||
return Token.BECOMES;
|
||||
} else
|
||||
return Token.COLON;
|
||||
|
||||
case ';':
|
||||
takeIt();
|
||||
return Token.SEMICOLON;
|
||||
|
||||
case ',':
|
||||
takeIt();
|
||||
return Token.COMMA;
|
||||
|
||||
case '~':
|
||||
takeIt();
|
||||
return Token.IS;
|
||||
|
||||
case '(':
|
||||
takeIt();
|
||||
return Token.LPAREN;
|
||||
|
||||
case ')':
|
||||
takeIt();
|
||||
return Token.RPAREN;
|
||||
|
||||
case '[':
|
||||
takeIt();
|
||||
return Token.LBRACKET;
|
||||
|
||||
case ']':
|
||||
takeIt();
|
||||
return Token.RBRACKET;
|
||||
|
||||
case '{':
|
||||
takeIt();
|
||||
return Token.LCURLY;
|
||||
|
||||
case '}':
|
||||
takeIt();
|
||||
return Token.RCURLY;
|
||||
|
||||
case SourceFile.EOT:
|
||||
return Token.EOT;
|
||||
|
||||
default:
|
||||
takeIt();
|
||||
return Token.ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
public Token scan() {
|
||||
Token tok;
|
||||
SourcePosition pos;
|
||||
int kind;
|
||||
|
||||
currentlyScanningToken = false;
|
||||
while (currentChar == '!'
|
||||
|| currentChar == ' '
|
||||
|| currentChar == '\n'
|
||||
|| currentChar == '\r'
|
||||
|| currentChar == '\t')
|
||||
scanSeparator();
|
||||
|
||||
currentlyScanningToken = true;
|
||||
currentSpelling = new StringBuffer("");
|
||||
pos = new SourcePosition();
|
||||
pos.start = sourceFile.getCurrentLine();
|
||||
|
||||
kind = scanToken();
|
||||
|
||||
pos.finish = sourceFile.getCurrentLine();
|
||||
tok = new Token(kind, currentSpelling.toString(), pos);
|
||||
if (debug)
|
||||
System.out.println(tok);
|
||||
return tok;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* @(#)SourceFile.java 2.1 2003/10/07
|
||||
*
|
||||
* Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown
|
||||
* Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland
|
||||
* and School of Computer and Math Sciences, The Robert Gordon University,
|
||||
* St. Andrew Street, Aberdeen AB25 1HG, Scotland.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is provided free for educational use only. It may
|
||||
* not be used for commercial purposes without the prior written permission
|
||||
* of the authors.
|
||||
*/
|
||||
|
||||
package Triangle.SyntacticAnalyzer;
|
||||
|
||||
public class SourceFile {
|
||||
|
||||
public static final char EOL = '\n';
|
||||
public static final char EOT = '\u0000';
|
||||
|
||||
java.io.File sourceFile;
|
||||
java.io.FileInputStream source;
|
||||
int currentLine;
|
||||
|
||||
public SourceFile(String filename) {
|
||||
try {
|
||||
sourceFile = new java.io.File(filename);
|
||||
source = new java.io.FileInputStream(sourceFile);
|
||||
currentLine = 1;
|
||||
} catch (java.io.IOException s) {
|
||||
sourceFile = null;
|
||||
source = null;
|
||||
currentLine = 0;
|
||||
}
|
||||
}
|
||||
|
||||
char getSource() {
|
||||
try {
|
||||
int c = source.read();
|
||||
|
||||
if (c == -1) {
|
||||
c = EOT;
|
||||
} else if (c == EOL) {
|
||||
currentLine++;
|
||||
}
|
||||
return (char) c;
|
||||
} catch (java.io.IOException s) {
|
||||
return EOT;
|
||||
}
|
||||
}
|
||||
|
||||
int getCurrentLine() {
|
||||
return currentLine;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* @(#)SourcePosition.java 2.1 2003/10/07
|
||||
*
|
||||
* Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown
|
||||
* Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland
|
||||
* and School of Computer and Math Sciences, The Robert Gordon University,
|
||||
* St. Andrew Street, Aberdeen AB25 1HG, Scotland.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is provided free for educational use only. It may
|
||||
* not be used for commercial purposes without the prior written permission
|
||||
* of the authors.
|
||||
*/
|
||||
|
||||
package Triangle.SyntacticAnalyzer;
|
||||
|
||||
public class SourcePosition {
|
||||
|
||||
public int start, finish;
|
||||
|
||||
public SourcePosition() {
|
||||
start = 0;
|
||||
finish = 0;
|
||||
}
|
||||
|
||||
public SourcePosition(int s, int f) {
|
||||
start = s;
|
||||
finish = f;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "(" + start + ", " + finish + ")";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* @(#)SyntaxError.java 2.1 2003/10/07
|
||||
*
|
||||
* Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown
|
||||
* Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland
|
||||
* and School of Computer and Math Sciences, The Robert Gordon University,
|
||||
* St. Andrew Street, Aberdeen AB25 1HG, Scotland.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is provided free for educational use only. It may
|
||||
* not be used for commercial purposes without the prior written permission
|
||||
* of the authors.
|
||||
*/
|
||||
|
||||
package Triangle.SyntacticAnalyzer;
|
||||
|
||||
class SyntaxError extends Exception {
|
||||
|
||||
SyntaxError() {
|
||||
super();
|
||||
};
|
||||
|
||||
SyntaxError(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* @(#)Token.java 2.1 2003/10/07
|
||||
*
|
||||
* Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown
|
||||
* Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland
|
||||
* and School of Computer and Math Sciences, The Robert Gordon University,
|
||||
* St. Andrew Street, Aberdeen AB25 1HG, Scotland.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is provided free for educational use only. It may
|
||||
* not be used for commercial purposes without the prior written permission
|
||||
* of the authors.
|
||||
*/
|
||||
|
||||
package Triangle.SyntacticAnalyzer;
|
||||
|
||||
final class Token extends Object {
|
||||
|
||||
protected int kind;
|
||||
protected String spelling;
|
||||
protected SourcePosition position;
|
||||
|
||||
public Token(int kind, String spelling, SourcePosition position) {
|
||||
|
||||
if (kind == Token.IDENTIFIER) {
|
||||
int currentKind = firstReservedWord;
|
||||
boolean searching = true;
|
||||
|
||||
while (searching) {
|
||||
int comparison = tokenTable[currentKind].compareTo(spelling);
|
||||
if (comparison == 0) {
|
||||
this.kind = currentKind;
|
||||
searching = false;
|
||||
} else if (comparison > 0 || currentKind == lastReservedWord) {
|
||||
this.kind = Token.IDENTIFIER;
|
||||
searching = false;
|
||||
} else {
|
||||
currentKind++;
|
||||
}
|
||||
}
|
||||
} else
|
||||
this.kind = kind;
|
||||
|
||||
this.spelling = spelling;
|
||||
this.position = position;
|
||||
|
||||
}
|
||||
|
||||
public static String spell(int kind) {
|
||||
return tokenTable[kind];
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Kind=" + kind + ", spelling=" + spelling +
|
||||
", position=" + position;
|
||||
}
|
||||
|
||||
// Token classes...
|
||||
|
||||
public static final int
|
||||
|
||||
// literals, identifiers, operators...
|
||||
INTLITERAL = 0,
|
||||
CHARLITERAL = 1,
|
||||
IDENTIFIER = 2,
|
||||
OPERATOR = 3,
|
||||
|
||||
// reserved words - must be in alphabetical order...
|
||||
ARRAY = 4,
|
||||
BEGIN = 5,
|
||||
CONST = 6,
|
||||
DO = 7,
|
||||
ELSE = 8,
|
||||
END = 9,
|
||||
FUNC = 10,
|
||||
IF = 11,
|
||||
IN = 12,
|
||||
LET = 13,
|
||||
OF = 14,
|
||||
PROC = 15,
|
||||
RECORD = 16,
|
||||
THEN = 17,
|
||||
TYPE = 18,
|
||||
VAR = 19,
|
||||
WHILE = 20,
|
||||
|
||||
// punctuation...
|
||||
DOT = 21,
|
||||
COLON = 22,
|
||||
SEMICOLON = 23,
|
||||
COMMA = 24,
|
||||
BECOMES = 25,
|
||||
IS = 26,
|
||||
|
||||
// brackets...
|
||||
LPAREN = 27,
|
||||
RPAREN = 28,
|
||||
LBRACKET = 29,
|
||||
RBRACKET = 30,
|
||||
LCURLY = 31,
|
||||
RCURLY = 32,
|
||||
|
||||
// special tokens...
|
||||
EOT = 33,
|
||||
ERROR = 34;
|
||||
|
||||
private static String[] tokenTable = new String[] {
|
||||
"<int>",
|
||||
"<char>",
|
||||
"<identifier>",
|
||||
"<operator>",
|
||||
"array",
|
||||
"begin",
|
||||
"const",
|
||||
"do",
|
||||
"else",
|
||||
"end",
|
||||
"func",
|
||||
"if",
|
||||
"in",
|
||||
"let",
|
||||
"of",
|
||||
"proc",
|
||||
"record",
|
||||
"then",
|
||||
"type",
|
||||
"var",
|
||||
"while",
|
||||
".",
|
||||
":",
|
||||
";",
|
||||
",",
|
||||
":=",
|
||||
"~",
|
||||
"(",
|
||||
")",
|
||||
"[",
|
||||
"]",
|
||||
"{",
|
||||
"}",
|
||||
"",
|
||||
"<error>"
|
||||
};
|
||||
|
||||
private final static int firstReservedWord = Token.ARRAY,
|
||||
lastReservedWord = Token.WHILE;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user