Page 1 of 1

about CASE string OF

Posted: Sun Aug 11, 2019 3:57 pm
by luowy
Is anyone interested in CASE string OF ?
e.g.

Code: Select all

MODULE ObxTest;
	IMPORT Log := StdLog;
	PROCEDURE Do* ();
		VAR str: ARRAY 12 OF CHAR;
	BEGIN
		str := "hello5";
		CASE str OF
		| "hello", "hello2", 'book': 
			Log.String('world'); Log.Ln;
		| "world": 
			Log.String('hello'); Log.Ln;
	 	(*ELSE*)
		END;
	END Do;

END ObxTest.
I find the MasterColorScanner has such code

Code: Select all

	PROCEDURE (scanner: Scanner) GetAttributes (IN str: ARRAY OF CHAR): 
		TextModels.Attributes, NEW;
		VAR a: TextModels.Attributes;
	BEGIN
		a := scanner.syntax.Ident;
		
		IF (str$ = "PROCEDURE") THEN
			a := scanner.syntax.KeyWord;
			state := regular;
			(* интерпретировать звездочку как маркер экспорта *)
			stateExport := exportCare;
			
		ELSIF (str$ = "VAR") OR (str$ = "TYPE") OR (str$ = "CONST")THEN
			a := scanner.syntax.KeyWord;
			state := regular;
			(* интерпретировать звездочку как маркер экспорта *)
			stateExport := exportCare;
			
		ELSIF(str$ = "BEGIN")THEN
			a := scanner.syntax.KeyWord;
			state := regular;
			stateExport := regular;
			
		ELSIF(str$ = "END")THEN
			a := scanner.syntax.KeyWord;
			
			IF state = declare THEN
				stateExport := exportCare;
			ELSE
				state := regular;
			END;
		
		ELSIF
			(str$ = "MODULE") 
			OR (str$ = "DEFINITION") OR (str$ = "IMPORT") 
			OR (str$ = "CLOSE") OR (str$ = "ARRAY")
			OR (str$ = "IF") OR (str$ = "THEN")
			OR (str$ = "ELSIF") OR (str$ = "ELSE") OR (str$ = "REPEAT")
			OR (str$ = "UNTIL") OR (str$ = "WHILE") OR (str$ = "DO")
			OR (str$ = "LOOP") OR (str$ = "FOR") OR (str$ = "TO") OR (str$ = "BY")
			OR (str$ = "POINTER") OR (str$ = "OF") OR (str$ = "CASE")
			OR (str$ = "WITH") OR (str$ = "MENU") OR (str$ = "SEPARATOR")
		THEN
			a := scanner.syntax.KeyWord;
			state := regular;
			
		ELSIF (str$ = "RECORD")  
		THEN
			a := scanner.syntax.KeyWord;
			state := regular;
			IF stateExport = declare THEN
				(* разблокируем для выделения жирным идентификаторов в полях записей *)
				stateExport := exportCare
			END
			
		ELSIF (str$ = "RETURN") OR (str$ = "EXIT") OR (str$ = "HALT") 
			OR (str$ = "ASSERT")
		THEN
			a := scanner.syntax.Exit;
			state := regular;
			
		ELSIF (str$ = "BYTE") OR (str$ = "CARDINAL") OR (str$ = "CHAR")
			OR (str$ = "INTEGER") OR (str$ = "LONGCARD") OR (str$ = "LONGINT")
			OR (str$ = "REAL") OR (str$ = "BOOLEAN") OR (str$ = "SET") OR (str$ = "STRING")
			OR (str$ = "SHORTCARD") OR (str$ = "SHORTCHAR") OR (str$ = "SHORTINT")
			OR (str$ = "SHORTREAL") OR (str$ = "LONGREAL") OR (str$ = "HUGEINT")
			OR (str$ = "LONGSET") OR (str$ = "ANYPTR") OR (str$ = "ANYREC")
		THEN
			a := scanner.syntax.PrimeType;
			state := regular;
			
		ELSIF (state = systemDot) & ((str$ = "ADR") OR (str$ = "LSH")
				OR (str$ = "ROT") OR (str$ = "TYP") OR (str$ = "VAL") OR (str$ = "GET")
				OR (str$ = "PUT") OR (str$ = "MOVE")
				OR (str$ = "SIZE") OR (str$ = "BIT") OR (str$ = "COPY")) (* O7 *)
		THEN
			a := scanner.syntax.SystemMod;
			state := regular;
			
		ELSIF (str$ = "OR") OR (str$ = "DIV") OR (str$ = "MOD") OR (str$ = "DIV0")
			OR (str$ = "REM0") OR (str$ = "ORD") OR (str$ = "CHR") OR (str$ = "ODD")
			OR (str$ = "MAX") OR (str$ = "MIN") OR (str$ = "INC") OR (str$ = "DEC")
			OR (str$ = "INCL") OR (str$ = "EXCL") OR (str$ = "LEN") OR (str$ = "ABS")
			OR (str$ = "BITS") OR (str$ = "SHORT") OR (str$ = "SIZE") OR (str$ = "LONG")
			OR (str$ = "ENTIER") OR (str$ = "CAP") OR (str$ = "ASH") OR (str$ = "IS")
			OR (str$ = "IN") OR (str$ = "OUT") OR (str$ = "COPY") OR (str$ = "FLOOR")
			OR (str$ = "FLT") OR (str$ = "ASR") OR (str$ = "LSL") OR (str$ = "ROR")
		THEN
			a := scanner.syntax.Oper;
			state := regular;
			
		ELSIF (str$ = "NEW") OR (str$ = "FINALIZE") OR (str$ = "ABSTRACT")
			OR (str$ = "EXTENSIBLE") OR (str$ = "LIMITED") OR (str$ = "EMPTY") OR (str$ = "DISPOSE")
		THEN
			a := scanner.syntax.New;
			state := regular;
			
		ELSIF (str$ = "NIL") OR (str$ = "TRUE") OR (str$ = "FALSE") 
			OR (str$ = "INF") 
		THEN
			a := scanner.syntax.Const;
			state := regular;
			
		ELSIF (str$ = "SYSTEM") THEN
			a := scanner.syntax.SystemMod;
			state := system; (* после SYSTEM чувствуем SIZE иначе *)
				
		END;
		
		RETURN a;
	END GetAttributes;
This code is a bit mess,
many modern languages have the syntax of "case/switch string" , but CP not;
I have done a simple patch for this syntax,but not sure our community like it or not.
wellcome someone who interesting it to test and improve it;

luowy

Re: about CASE string OF

Posted: Sun Aug 11, 2019 5:13 pm
by adimetrius
luowy,
What specifically do you think is ugly in that text - I mean with a cascading IF..ELSIF..END?

Re: about CASE string OF

Posted: Mon Aug 12, 2019 3:37 am
by luowy
I mean a bit mess , sometimes CASE is more readable and writable than IF... ESLIF ....
e.g.

Code: Select all

      IF (str$ = "PROCEDURE") THEN
         a := scanner.syntax.KeyWord;
         state := regular;
         (* интерпретировать звездочку как маркер экспорта *)
         stateExport := exportCare;
         
      ELSIF (str$ = "VAR") OR (str$ = "TYPE") OR (str$ = "CONST")THEN
         a := scanner.syntax.KeyWord;
         state := regular;
         (* интерпретировать звездочку как маркер экспорта *)
         stateExport := exportCare;
         
      ELSIF(str$ = "BEGIN")THEN
         a := scanner.syntax.KeyWord;
         state := regular;
         stateExport := regular;
         
      ELSIF(str$ = "END")THEN
         a := scanner.syntax.KeyWord;
         
         IF state = declare THEN
            stateExport := exportCare;
         ELSE
            state := regular;
         END;
      
      ELSIF
         (str$ = "MODULE") 
         OR (str$ = "DEFINITION") OR (str$ = "IMPORT") 
         OR (str$ = "CLOSE") OR (str$ = "ARRAY")
         OR (str$ = "IF") OR (str$ = "THEN")
         OR (str$ = "ELSIF") OR (str$ = "ELSE") OR (str$ = "REPEAT")
         OR (str$ = "UNTIL") OR (str$ = "WHILE") OR (str$ = "DO")
         OR (str$ = "LOOP") OR (str$ = "FOR") OR (str$ = "TO") OR (str$ = "BY")
         OR (str$ = "POINTER") OR (str$ = "OF") OR (str$ = "CASE")
         OR (str$ = "WITH") OR (str$ = "MENU") OR (str$ = "SEPARATOR")
      THEN
         a := scanner.syntax.KeyWord;
         state := regular;
        
same code as above

Code: Select all

	  CASE  str OF
	  |"PROCEDURE":
	     a := scanner.syntax.KeyWord;
         state := regular;
         (* интерпретировать звездочку как маркер экспорта *)
         stateExport := exportCare;
         
     |"VAR",  "TYPE",  "CONST":
         a := scanner.syntax.KeyWord;
         state := regular;
         (* интерпретировать звездочку как маркер экспорта *)
         stateExport := exportCare;
         
      |"BEGIN":
         a := scanner.syntax.KeyWord;
         state := regular;
         stateExport := regular;
         
     |"END":
         a := scanner.syntax.KeyWord;
         
         IF state = declare THEN
            stateExport := exportCare;
         ELSE
            state := regular;
         END;
      
     | "MODULE","DEFINITION",  "IMPORT",  "CLOSE",  "ARRAY",
         "IF",  "THEN","ELSIF",  "ELSE",  "REPEAT","UNTIL",  "WHILE", 
         "DO", "LOOP",  "FOR",  "TO",  "BY", "POINTER",  "OF",  "CASE", 
        "WITH",  "MENU",  "SEPARATOR":

         a := scanner.syntax.KeyWord;
         state := regular;
         

Re: about CASE string OF

Posted: Mon Aug 12, 2019 4:01 am
by Ivan Denisov
I think, that it is good and can be legal. Does this syntax generates faster code? This should be possible.

Re: about CASE string OF

Posted: Mon Aug 12, 2019 7:00 am
by luowy
Ivan Denisov wrote: Does this syntax generates faster code?
no, as same as the if..elsif..end;
I have writed an improved one,output like:

Code: Select all

	PROCEDURE Keyword(VAR name: ARRAY OF CHAR; VAR sym,c: BYTE);
	BEGIN
		sym:=ident;
		CASE name[0] OF
		| "A": 
			IF name = "ARRAY" THEN sym := array 
			END
		| "B": 
			IF name = "BEGIN" THEN sym := begin
			ELSIF name = "BY" THEN sym := by
			END
		| "C": 
			IF name = "CASE" THEN sym := case
			ELSIF name = "CONST" THEN sym := const
			ELSIF name = "CLOSE" THEN sym := close
			END
		| "D": 
			IF name = "DO" THEN sym := do
			ELSIF name = "DIV" THEN sym := div
			END
		| "E": 
			IF name = "END" THEN sym := end
			ELSIF name = "ELSE" THEN sym := else
			ELSIF name = "ELSIF" THEN sym := elsif
			ELSIF name = "EXIT" THEN sym := exit
			END
		| "F": IF name = "FOR" THEN sym := for END
		| "I": 
			IF name = "IF" THEN sym := if
			ELSIF name = "IN" THEN sym := in
			ELSIF name = "IS" THEN sym := is
			ELSIF name = "IMPORT" THEN sym := import
			END
		| "L": 
			IF name = "LOOP" THEN sym := loop 
			END
		| "M": 
			IF name = "MOD" THEN sym := mod
			ELSIF name = "MODULE" THEN sym := module
			END
		| "N": IF name = "NIL" THEN sym := nil END
		| "O": 
			IF name = "OR" THEN sym := or
			ELSIF name = "OF" THEN sym := of
			ELSIF name = "OUT" THEN sym := out
			END
		| "P": 
			IF name = "PROCEDURE" THEN sym := procedure
			ELSIF name = "POINTER" THEN sym := pointer
			END
		| "R": 
			IF name = "RECORD" THEN sym := record
			ELSIF name = "REPEAT" THEN sym := repeat
			ELSIF name = "RETURN" THEN sym := return
			END
		| "T": 
			IF name = "THEN" THEN sym := then
			ELSIF name = "TO" THEN sym := to
			ELSIF name = "TYPE" THEN sym := type
			END
		| "U": IF name = "UNTIL" THEN sym := until END
		| "V": IF name = "VAR" THEN sym := var END
		| "W": 
			IF name = "WHILE" THEN sym := while
			ELSIF name = "WITH" THEN sym := with
			END
		ELSE 
		END;
		IF sym = ident THEN c:=idents; ELSE c :=keywords  END;
	END Keyword;
But its implementation is a bit complicated, and Its output code size is a bit larger, I gave up it.

Re: about CASE string OF

Posted: Mon Aug 12, 2019 11:52 am
by cfbsoftware
I also use the technique:

Code: Select all

      CASE name[0] OF
      | "A": 
         IF name = "ARRAY" THEN sym := array 
etc.
in the Astrobe compilers. It is the most efficient of the suggestions here. It is also used in the BlackBox compiler (Dev\CPS.odc) and John Gough's Gardens Point Component Pascal compiler. Look for Procedure CheckLiteral:

https://github.com/k-john-gough/gpcp/bl ... PascalS.cp

However, Wirth uses a different technique altogether to search for keywords in his latest Oberon compiler. He uses the length of the string to limit the number of items that need to be searched.

Look for the uses and definition of the function EnterKW which creates the keyword table and the procedure Identifier that searches it:

https://people.inf.ethz.ch/wirth/Projec ... RS.Mod.txt

Re: about CASE string OF

Posted: Mon Aug 12, 2019 4:48 pm
by luowy
cfbsoftware wrote:Wirth uses a different technique altogether to search for keywords in his latest Oberon compiler. He uses the length of the string to limit the number of items that need to be searched.
thanks, I will try .
but first I need to understand the condition alogrithm and pseudo output of the "useTree", "useTable".

Re: about CASE string OF

Posted: Fri Aug 16, 2019 10:16 am
by luowy
the improved one has finished, almost same size and speed as handwritten code,Welcome to test and feedback.

Re: about CASE string OF

Posted: Tue Aug 20, 2019 11:29 am
by Ivan Denisov
luowy wrote:the improved one has finished, almost same size and speed as handwritten code,Welcome to test and feedback.
Speed is very good and syntax is better. IMHO, this can be the part of BlackBox.