Vladislav Folts 10 лет назад
Родитель
Сommit
76238e3810
8 измененных файлов с 143 добавлено и 35 удалено
  1. BIN
      bin/compiled.zip
  2. 1 10
      src/context.js
  3. 1 5
      src/grammar.js
  4. 0 2
      src/ob/Context.ob
  5. 4 2
      src/ob/ContextHierarchy.ob
  6. 113 14
      src/ob/Lexer.ob
  7. 8 0
      src/ob/String.ob
  8. 16 2
      test/test_unit.js

BIN
bin/compiled.zip


+ 1 - 10
src/context.js

@@ -31,7 +31,6 @@ ChainedContext.prototype.init = ContextHierarchy.Node;
 exports.Integer = ChainedContext.extend({
     init: function IntegerContext(context){
         ChainedContext.prototype.init.call(this, context);
-        this.attributes = {};
     },
     endParse: function(){
         var n = this.attributes.int;
@@ -42,17 +41,9 @@ exports.Integer = ChainedContext.extend({
 exports.Real = ChainedContext.extend({
     init: function RealContext(context){
         ChainedContext.prototype.init.call(this, context);
-        this.__result = "";
-    },
-    isLexem: function(){return true;},
-    handleChar: function(c){this.__result += String.fromCharCode(c);},
-    handleLiteral: function(s){
-        if (s == "D") // LONGREAL
-            s = "E";
-        this.__result += s;
     },
     endParse: function(){
-        var n = Number(this.__result);
+        var n = this.attributes.real;
         this.parent().handleConst(basicTypes.real, Code.makeRealConst(n), n.toString());
     }
 });

+ 1 - 5
src/grammar.js

@@ -67,11 +67,7 @@ var identList = and(identdef, repeat(and(",", identdef)));
 var variableDeclaration = context(and(identList, ":", type), contexts.variableDeclaration);
 
 var integer = context(Lexer.integer, Context.Integer);
-
-var scaleFactor = and(or("E", "D"), optional(or("+", "-")), digit, repeat(digit));
-var real = context(and(digit, repeat(digit), point, repeat(digit), optional(scaleFactor))
-                 , Context.Real);
-
+var real = context(Lexer.real, Context.Real);
 var number = or(real, integer);
 
 var string = or(context(Lexer.string, Context.String)

+ 0 - 2
src/ob/Context.ob

@@ -6,10 +6,8 @@ TYPE
         handleLiteral*: PROCEDURE(s: STRING);
         handleString*:  PROCEDURE(s: STRING);
         handleIdent*:   PROCEDURE(s: STRING);
-        isLexem*:       PROCEDURE(): BOOLEAN;
         qualifyScope*:  PROCEDURE(scope: ScopeBase.PType): STRING;
         
-        attributes*: MAP OF INTEGER;
         rtl*: OberonRtl.PType;
     END;
     PType* = POINTER TO Type;

+ 4 - 2
src/ob/ContextHierarchy.ob

@@ -16,7 +16,9 @@ TYPE
         code: STRING;
     END;
 
-    Attributes = POINTER TO RECORD
+    Attributes* = RECORD
+        int*: INTEGER;
+        real*: REAL;
     END;
 
     Node* = RECORD
@@ -31,7 +33,7 @@ TYPE
         PROCEDURE genTypeName(): STRING;
 
         mParent: PNode;
-        attributes: Attributes;
+        attributes*: Attributes;
     END;
 
     Root* = RECORD(Node)

+ 113 - 14
src/ob/Lexer.ob

@@ -1,5 +1,5 @@
 MODULE Lexer;
-IMPORT Context, Errors, Stream, String;
+IMPORT Context, ContextHierarchy, Errors, Stream, String;
 
 CONST
     quote = 22X; (* " *)
@@ -29,7 +29,7 @@ END isDigit;
 
 PROCEDURE isLetter(c: CHAR): BOOLEAN;
     RETURN ((c >= "a") & (c <= "z")) OR ((c >= "A") & (c <= "Z"))
-END isLetter;
+END;
 
 PROCEDURE digit*(VAR stream: Stream.Type; context: Context.Type): BOOLEAN;
 VAR
@@ -46,7 +46,21 @@ BEGIN
     RETURN result
 END digit;
 
-PROCEDURE integer*(VAR stream: Stream.Type; VAR context: Context.Type): BOOLEAN;
+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 context: ContextHierarchy.Node): BOOLEAN;
 VAR
     hexDetected: BOOLEAN;
     dec, hex: INTEGER;
@@ -54,7 +68,7 @@ VAR
     PROCEDURE collect(c: CHAR): BOOLEAN;
     BEGIN
         d <- -1;
-        IF (c >= "0") & (c <= "9") THEN
+        IF isDigit(c) THEN
             d := ORD(c) - ORD("0");
         ELSIF (c >= "A") & (c <= "F") THEN
             d := ORD(c) - ORD("A") + 10;
@@ -82,11 +96,11 @@ BEGIN
             Errors.raise("integer constant looks like having hexadecimal format but 'H' suffix is missing");
         END;
 
-        IF Stream.eof(stream) OR ~isLetter(Stream.peekChar(stream)) THEN
+        IF peekSeparator(stream) THEN
             IF hexDetected THEN
-                context.attributes["int"] := hex;
+                context.attributes.int := hex;
             ELSE
-                context.attributes["int"] := dec;
+                context.attributes.int := dec;
             END;
         
             result := TRUE;
@@ -95,6 +109,93 @@ BEGIN
     RETURN result;
 END;
 
+PROCEDURE real*(VAR stream: Stream.Type; VAR context: ContextHierarchy.Node): 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") OR (c = "D")) 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
+            context.attributes.real := String.parseReal(s);
+            result := TRUE;
+        END
+    END;
+    RETURN result;
+END;
+
 PROCEDURE hexDigit*(VAR stream: Stream.Type; context: Context.Type): BOOLEAN;
 VAR
     result: BOOLEAN;
@@ -230,11 +331,10 @@ END readSpaces;
 
 PROCEDURE skipSpaces*(VAR stream: Stream.Type; context: Context.Type);
 BEGIN
-    IF (context.isLexem = NIL) OR ~context.isLexem() THEN
-        WHILE Stream.read(stream, readSpaces)
-            & skipComment(stream, context) DO END;
-    END
-END skipSpaces;
+    WHILE Stream.read(stream, readSpaces)
+        & skipComment(stream, context) DO 
+    END;
+END;
 
 PROCEDURE Literal.Literal(s: STRING)
     | s(s);
@@ -246,8 +346,7 @@ VAR
 BEGIN
     IF Stream.peekStr(stream, l.s) THEN
         Stream.next(stream, LEN(l.s));
-        IF ((context.isLexem # NIL) & context.isLexem())
-            OR ~isLetter(l.s[LEN(l.s) - 1])
+        IF     ~isLetter(l.s[LEN(l.s) - 1])
             OR Stream.eof(stream)
             OR (~isLetter(Stream.peekChar(stream)) & ~isDigit(Stream.peekChar(stream)))
                 THEN

+ 8 - 0
src/ob/String.ob

@@ -17,6 +17,14 @@ BEGIN
     RETURN result
 END fromInt;
 
+PROCEDURE parseReal*(s: STRING): REAL;
+VAR 
+    result: REAL;
+BEGIN
+    JS.do("result = JS.Number(s)");
+    RETURN result
+END;
+
 PROCEDURE indexOf*(self: STRING; c: CHAR): INTEGER;
 VAR 
     result: INTEGER;

+ 16 - 2
test/test_unit.js

@@ -560,7 +560,14 @@ return {
          ["1HH", "not parsed"],
          ["1H0", "not parsed"],
          ["1 23", "not parsed"],
-         ["1F FH", "integer constant looks like having hexadecimal format but 'H' suffix is missing"])
+         ["1F FH", "integer constant looks like having hexadecimal format but 'H' suffix is missing"]
+         )
+    ),
+"INTEGER number in statement": testWithGrammar(
+    grammar.statement,
+    pass("IF 1 < 2345 THEN END"),
+    fail(["IF 1 < 2345THEN END", "'BOOLEAN' expression expected, got 'INTEGER'"],
+         ["IF 1 < 2345HTHEN END", "'BOOLEAN' expression expected, got 'INTEGER'"])
     ),
 "SET statement": testWithContext(
     context(grammar.statement, "VAR s: SET;"),
@@ -577,7 +584,9 @@ return {
          "1.2345E6",
          "1.2345E+6",
          "1.2345E-12"),
-    fail(["1. 2345E-12", "not parsed"],
+    fail(["1..", "not parsed"],
+         ["1..2", "not parsed"],
+         ["1. 2345E-12", "not parsed"],
          ["1.23 45E-12", "not parsed"],
          ["1.2345 E-12", "not parsed"],
          ["1.2345E-1 2", "not parsed"])
@@ -588,6 +597,11 @@ return {
          "1.2345D+6",
          "1.2345D-6")
     ),
+"REAL number in statement": testWithGrammar(
+    grammar.statement,
+    pass("IF 1. < 1.2345 THEN END"),
+    fail(["IF 1. < 1.2345THEN END", "'BOOLEAN' expression expected, got 'REAL'"])
+    ),
 "IF statement": testWithContext(
     context(grammar.statement,
             "VAR b1: BOOLEAN; i1: INTEGER; p: POINTER TO RECORD END;"),