Initial commit of version 2.1.

This commit is contained in:
Deryck Brown
2022-05-11 21:29:12 +01:00
parent d81805bc2e
commit baf478a7a7
122 changed files with 8977 additions and 0 deletions
@@ -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;
}