Browse Source

+ modeswitch UNDERSCOREISSEPERATOR, active by default in delphi modes:
support _ as seperator in numbers, it is ignored while reading them, resolves #39504

florian 3 years ago
parent
commit
d2447026de

+ 1 - 1
compiler/globals.pas

@@ -55,7 +55,7 @@ interface
           m_pointer_2_procedure,m_autoderef,m_tp_procvar,m_initfinal,m_default_ansistring,
           m_out,m_default_para,m_duplicate_names,m_hintdirective,
           m_property,m_default_inline,m_except,m_advanced_records,
-          m_array_operators,m_prefixed_attributes];
+          m_array_operators,m_prefixed_attributes,m_underscoreisseperator];
        delphiunicodemodeswitches = delphimodeswitches + [m_systemcodepage,m_default_unicodestring];
        fpcmodeswitches =
          [m_fpc,m_string_pchar,m_nested_comment,m_repeat_forward,

+ 5 - 3
compiler/globtype.pas

@@ -527,7 +527,8 @@ interface
          m_array_operators,     { use Delphi compatible array operators instead of custom ones ("+") }
          m_multi_helpers,       { helpers can appear in multiple scopes simultaneously }
          m_array2dynarray,      { regular arrays can be implicitly converted to dynamic arrays }
-         m_prefixed_attributes  { enable attributes that are defined before the type they belong to }
+         m_prefixed_attributes, { enable attributes that are defined before the type they belong to }
+         m_underscoreisseperator{ _ can be used as seperator to group digits in numbers }
        );
        tmodeswitches = set of tmodeswitch;
 
@@ -678,7 +679,7 @@ interface
 
        cstylearrayofconst = [pocall_cdecl,pocall_cppdecl,pocall_mwpascal,pocall_sysv_abi_cdecl,pocall_ms_abi_cdecl];
 
-       modeswitchstr : array[tmodeswitch] of string[18] = ('',
+       modeswitchstr : array[tmodeswitch] of string[21] = ('',
          '','','','','','','',
          {$ifdef gpc_mode}'',{$endif}
          { more specific }
@@ -719,7 +720,8 @@ interface
          'ARRAYOPERATORS',
          'MULTIHELPERS',
          'ARRAYTODYNARRAY',
-         'PREFIXEDATTRIBUTES'
+         'PREFIXEDATTRIBUTES',
+         'UNDERSCOREISSEPERATOR'
          );
 
 

+ 19 - 7
compiler/scanner.pas

@@ -4198,6 +4198,7 @@ type
       var
         base,
         i  : longint;
+        firstdigitread: Boolean;
       begin
         case c of
           '%' :
@@ -4227,17 +4228,20 @@ type
               i:=0;
             end;
         end;
+        firstdigitread:=false;
         while ((base>=10) and (c in ['0'..'9'])) or
               ((base=16) and (c in ['A'..'F','a'..'f'])) or
               ((base=8) and (c in ['0'..'7'])) or
-              ((base=2) and (c in ['0'..'1'])) do
+              ((base=2) and (c in ['0'..'1'])) or
+              ((m_underscoreisseperator in current_settings.modeswitches) and firstdigitread and (c='_')) do
          begin
-           if i<255 then
+           if (i<255) and (c<>'_') then
             begin
               inc(i);
               pattern[i]:=c;
             end;
            readchar;
+           firstdigitread:=true;
          end;
         pattern[0]:=chr(i);
       end;
@@ -4795,7 +4799,7 @@ type
         m       : longint;
         mac     : tmacro;
         asciinr : string[33];
-        iswidestring : boolean;
+        iswidestring , firstdigitread: boolean;
       label
          exit_label;
       begin
@@ -5006,10 +5010,14 @@ type
                            begin
                              { insert the number after the . }
                              pattern:=pattern+'.';
-                             while c in ['0'..'9'] do
+                             firstdigitread:=false;
+                             while (c in ['0'..'9']) or
+                              ((m_underscoreisseperator in current_settings.modeswitches) and firstdigitread and (c='_')) do
                               begin
-                                pattern:=pattern+c;
+                                if c<>'_' then
+                                  pattern:=pattern+c;
                                 readchar;
+                                firstdigitread:=true;
                               end;
                            end;
                          else
@@ -5031,11 +5039,15 @@ type
                           readchar;
                         end;
                        if not(c in ['0'..'9']) then
-                        Illegal_Char(c);
-                       while c in ['0'..'9'] do
+                         Illegal_Char(c);
+                       firstdigitread:=false;
+                       while (c in ['0'..'9']) or
+                        ((m_underscoreisseperator in current_settings.modeswitches) and firstdigitread and (c='_')) do
                         begin
+                          if c<>'_' then
                           pattern:=pattern+c;
                           readchar;
+                          firstdigitread:=true;
                         end;
                      end;
                     token:=_REALNUMBER;

+ 2 - 1
compiler/utils/ppuutils/ppudump.pp

@@ -2426,7 +2426,8 @@ const
          'm_array_operators',     { use Delphi compatible array operators instead of custom ones ("+") }
          'm_multi_helpers',       { helpers can appear in multiple scopes simultaneously }
          'm_array2dynarray',      { regular arrays can be implicitly converted to dynamic arrays }
-         'm_prefixed_attributes'  { enable attributes that are defined before the type they belong to }
+         'm_prefixed_attributes', { enable attributes that are defined before the type they belong to }
+         'm_underscoreisseperator'{ _ can be used as seperator to group digits in numbers }
        );
        { optimizer }
        optimizerswitchname : array[toptimizerswitch] of string[50] =

+ 5 - 0
tests/tbf/tb0286.pp

@@ -0,0 +1,5 @@
+{ %fail }
+
+begin
+  writeln(123_567);
+end.

+ 6 - 0
tests/tbf/tb0287.pp

@@ -0,0 +1,6 @@
+{ %fail }
+{$modeswitch underscoreisseperator}
+
+begin
+  writeln(_123567);
+end.

+ 6 - 0
tests/tbf/tb0288.pp

@@ -0,0 +1,6 @@
+{ %fail }
+{$modeswitch underscoreisseperator}
+
+begin
+  writeln($_123567);
+end.

+ 6 - 0
tests/tbf/tb0289.pp

@@ -0,0 +1,6 @@
+{ %fail }
+{$modeswitch underscoreisseperator}
+
+begin
+  writeln(123567._1234);
+end.

+ 6 - 0
tests/tbf/tb0290.pp

@@ -0,0 +1,6 @@
+{ %fail }
+{$modeswitch underscoreisseperator}
+
+begin
+  writeln(123567.1234e_12);
+end.

+ 48 - 0
tests/tbs/ib0690.inc

@@ -0,0 +1,48 @@
+const
+  ic1 = %1001_1001;
+  ic2 = %101_101;
+  ic3 = &1201_1002;
+  ic4 = &121_102;
+  ic5 = 1_123_123;
+  ic6 = 1_1235_1235;
+  ic7 = $1_123_123;  
+  ic8 = $1_12354;
+  rc1 = 1_1235_1235;
+  rc2 = 1_123_123.000_000;
+  rc3 = 1_1234_1234.0000_0000;
+  rc4 = 1_123_123.000_000e1_2;
+  rc5 = 1_1234_1234.0000_0000e1_2;
+var
+  i : Int64;  
+  r : Real;
+begin
+  i:=%1001_1001;
+  i:=%101_101;
+  i:=&1201_1002;
+  i:=&121_102;
+  i:=1_123_123;
+  i:=1_1235_1235;
+  i:=$1_123_123;  
+  i:=$1_12354;
+  r:=1_1235_1235;
+  r:=1_123_123.000_000;
+  r:=1_1234_1234.0000_0000;
+  r:=1_123_123.000_000e1_2;
+  r:=1_1234_1234.0000_0000e1_2;
+  
+{$if rc1=1_1235_1235}
+  r:=1;
+{$endif r=1_1235_1235}
+{$if rc2=1_123_123.000_000}
+  r:=1;
+{$endif r=1_1235_1235}
+{$if rc3=1_1234_1234.0000_0000}
+  r:=1;
+{$endif r=1_1235_1235}
+{$if rc4=1_123_123.000_000e1_2}
+  r:=1;
+{$endif r=1_123_123.000_000e1_2}
+{$if rc5=1_1234_1234.0000_0000}
+  r:=1;
+{$endif r=1_1234_1234.0000_0000}
+end.

+ 4 - 0
tests/tbs/tb0690.pp

@@ -0,0 +1,4 @@
+{ %norun }
+{$modeswitch underscoreisseperator}
+
+{$i ib0690.inc}

+ 4 - 0
tests/tbs/tb0691.pp

@@ -0,0 +1,4 @@
+{ %norun }
+{$mode delphi}
+
+{$i ib0690.inc}