123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- MODULE Lexer;
- IMPORT
- Chars, ContextExpression, ContextHierarchy, Errors, Stream, String;
- CONST
- doubleQuote = Chars.doubleQuote;
- commentBegin = "(*";
- commentEnd = "*)";
- TYPE
- Literal* = RECORD
- PROCEDURE Literal*(s: STRING);
- s: STRING
- END;
- PROCEDURE isDigit(c: CHAR): BOOLEAN;
- RETURN (c >= "0") & (c <= "9")
- END;
- PROCEDURE isLetter(c: CHAR): BOOLEAN;
- RETURN ((c >= "a") & (c <= "z")) OR ((c >= "A") & (c <= "Z"))
- END;
- PROCEDURE peekSeparator(VAR stream: Stream.Type): BOOLEAN;
- BEGIN
- result <- TRUE;
- IF ~Stream.eof(stream) THEN
- c <- Stream.peekChar(stream);
- IF isLetter(c) THEN
- result := FALSE;
- ELSIF c = "." THEN
- result := Stream.peekStr(stream, "..");
- END;
- END;
- RETURN result;
- END;
- PROCEDURE integer*(VAR stream: Stream.Type; VAR cx: ContextExpression.Integer): BOOLEAN;
- VAR
- hexDetected: BOOLEAN;
- dec, hex: INTEGER;
- PROCEDURE collect(c: CHAR): BOOLEAN;
- BEGIN
- d <- -1;
- IF isDigit(c) THEN
- d := ORD(c) - ORD("0");
- ELSIF (c >= "A") & (c <= "F") THEN
- d := ORD(c) - ORD("A") + 10;
- hexDetected := TRUE;
- END;
- IF d # -1 THEN
- hex := hex * 16 + d;
- IF ~hexDetected THEN
- dec := dec * 10 + d;
- END;
- END;
- RETURN d # -1;
- END;
- BEGIN
- result <- FALSE;
- IF ~Stream.eof(stream) & collect(Stream.getChar(stream)) & ~hexDetected THEN
- WHILE ~Stream.eof(stream) & collect(Stream.peekChar(stream)) DO
- Stream.next(stream, 1);
- END;
- IF ~Stream.eof(stream) & (Stream.peekChar(stream) = "H") THEN
- hexDetected := TRUE;
- Stream.next(stream, 1);
- ELSIF hexDetected THEN
- Errors.raise("integer constant looks like having hexadecimal format but 'H' suffix is missing");
- END;
- IF peekSeparator(stream) THEN
- IF hexDetected THEN
- cx.handleInt(hex);
- ELSE
- cx.handleInt(dec);
- END;
-
- result := TRUE;
- END;
- END
- RETURN result;
- END;
- PROCEDURE real*(VAR stream: Stream.Type; VAR cx: ContextExpression.Real): BOOLEAN;
- VAR
- c: CHAR;
- s: STRING;
- PROCEDURE peekChar(): BOOLEAN;
- BEGIN
- result <- FALSE;
- IF ~Stream.eof(stream) THEN
- c := Stream.peekChar(stream);
- result := TRUE;
- END;
- RETURN result;
- END;
- PROCEDURE getChar(): BOOLEAN;
- BEGIN
- result <- FALSE;
- IF ~Stream.eof(stream) THEN
- c := Stream.getChar(stream);
- result := TRUE;
- END;
- RETURN result;
- END;
- PROCEDURE next();
- BEGIN
- Stream.next(stream, 1);
- END;
- PROCEDURE collectOptionalDigits();
- BEGIN
- WHILE peekChar() & isDigit(c) DO
- s := s + String.fromChar(c);
- next();
- END;
- END;
- PROCEDURE collectDigits(): BOOLEAN;
- BEGIN
- result <- FALSE;
- IF getChar() & isDigit(c) THEN
- s := s + String.fromChar(c);
- collectOptionalDigits();
- result := TRUE;
- END;
- RETURN result;
- END;
- PROCEDURE collectScale(): BOOLEAN;
-
- PROCEDURE collectPlusOrMinus();
- BEGIN
- IF peekChar() THEN
- IF c = "-" THEN
- s := s + "-";
- next();
- ELSIF c = "+" THEN
- next();
- END;
- END;
- END;
-
- BEGIN
- result <- TRUE;
- IF peekChar() & (c = "E") THEN
- s := s + "E";
- next();
- collectPlusOrMinus();
- result := collectDigits();
- END;
- RETURN result;
- END;
- BEGIN
- result <- FALSE;
- IF collectDigits() & getChar() & (c = ".") THEN
- s := s + ".";
- collectOptionalDigits();
- IF collectScale() & peekSeparator(stream) THEN
- cx.handleReal(String.parseReal(s));
- result := TRUE;
- END
- END;
- RETURN result;
- END;
- PROCEDURE isHexDigit(c: CHAR): BOOLEAN;
- RETURN isDigit(c) OR ((c >= "A") & (c <= "F"));
- END;
- PROCEDURE point*(VAR stream: Stream.Type; context: ContextHierarchy.Node): BOOLEAN;
- VAR result: BOOLEAN;
- BEGIN
- IF ~Stream.eof(stream)
- & (Stream.getChar(stream) = ".")
- & ( Stream.eof(stream)
- OR (Stream.peekChar(stream) # ".")) THEN (*not a diapason ".."*)
- context.handleLiteral(".");
- result := TRUE;
- END
- RETURN result;
- END;
- PROCEDURE string*(VAR stream: Stream.Type; VAR cx: ContextExpression.Str): BOOLEAN;
- PROCEDURE quotedString();
- VAR
- c: CHAR;
- s: STRING;
- BEGIN
- IF ~Stream.eof(stream) THEN
- c := Stream.getChar(stream);
- WHILE (c # doubleQuote) & ~Stream.eof(stream) DO
- IF c # doubleQuote THEN
- s := s + String.fromChar(c);
- END;
- c := Stream.getChar(stream);
- END;
- ELSE
- c := 0X;
- END;
-
- IF c # doubleQuote THEN
- Errors.raise("unexpected end of string");
- END;
-
- cx.handleStr(s);
- END;
- PROCEDURE hexString(firstChar: CHAR): BOOLEAN;
- BEGIN
- result <- FALSE;
- s <- String.fromChar(firstChar);
- WHILE ~Stream.eof(stream) & isHexDigit(Stream.peekChar(stream)) DO
- s := s + String.fromChar(Stream.getChar(stream));
- END;
- IF ~Stream.eof(stream) & (Stream.getChar(stream) = "X") THEN
- cx.handleStr(String.fromChar(CHR(String.parseHex(s))));
- result := TRUE;
- END;
- RETURN result;
- END;
- BEGIN
- result <- FALSE;
- IF ~Stream.eof(stream) THEN
- c <- Stream.getChar(stream);
- IF c = doubleQuote THEN
- quotedString();
- result := TRUE;
- ELSIF isDigit(c) THEN
- result := hexString(c);
- END
- END
- RETURN result
- END string;
- PROCEDURE ident*(VAR stream: Stream.Type; context: ContextHierarchy.Node; reservedWords: ARRAY OF STRING): BOOLEAN;
- VAR
- result: BOOLEAN;
- c: CHAR;
- s: STRING;
- BEGIN
- IF ~Stream.eof(stream) THEN
- c := Stream.getChar(stream);
- IF isLetter(c) THEN
- WHILE ~Stream.eof(stream) & (isLetter(c) OR isDigit(c)) DO (* OR c = "_" *)
- s := s + String.fromChar(c);
- c := Stream.getChar(stream);
- END;
- IF isLetter(c) OR isDigit(c) THEN
- s := s + String.fromChar(c);
- ELSE
- Stream.next(stream, -1);
- END;
- IF reservedWords.indexOf(s) = -1 THEN
- (*IF jsReservedWords.indexOf(s) # -1 THEN
- s := s + "$";
- END;*)
- context.handleIdent(s);
- result := TRUE;
- END
- END
- END
- RETURN result
- END ident;
- PROCEDURE skipComment(VAR stream: Stream.Type; context: ContextHierarchy.Node): BOOLEAN;
- VAR
- result: BOOLEAN;
- BEGIN
- IF Stream.peekStr(stream, commentBegin) THEN
- Stream.next(stream, LEN(commentBegin));
- WHILE ~Stream.peekStr(stream, commentEnd) DO
- IF ~skipComment(stream, context) THEN
- Stream.next(stream, 1);
- IF Stream.eof(stream) THEN
- Errors.raise("comment was not closed");
- END
- END
- END;
- Stream.next(stream, LEN(commentEnd));
- result := TRUE;
- END
- RETURN result
- END skipComment;
- PROCEDURE readSpaces(c: CHAR): BOOLEAN;
- RETURN (c = " ")
- OR (c = 8X)
- OR (c = 9X)
- OR (c = 0AX)
- OR (c = 0DX)
- END readSpaces;
- PROCEDURE skipSpaces*(VAR stream: Stream.Type; context: ContextHierarchy.Node);
- BEGIN
- WHILE Stream.read(stream, readSpaces)
- & skipComment(stream, context) DO
- END;
- END;
- PROCEDURE Literal.Literal(s: STRING)
- | s(s);
- END;
- PROCEDURE literal*(l: Literal; VAR stream: Stream.Type; context: ContextHierarchy.Node): BOOLEAN;
- VAR
- result: BOOLEAN;
- BEGIN
- IF Stream.peekStr(stream, l.s) THEN
- Stream.next(stream, LEN(l.s));
- IF ~isLetter(l.s[LEN(l.s) - 1])
- OR Stream.eof(stream)
- OR (~isLetter(Stream.peekChar(stream)) & ~isDigit(Stream.peekChar(stream)))
- THEN
- context.handleLiteral(l.s);
- result := TRUE;
- END;
- END;
- RETURN result
- END;
- END Lexer.
|