Jak pokolorować składnię Delphi używając funkcji PHP

Adam Boduch

Oto gotowa funkcja:

function _IsInArray($array, $element)
{
  return isset($array[$element]);
}
   
function _IsCharValid($c)
{
  if(($c >= 'a' && $c <= 'z') || ($c >= '0' && $c <= '9') || ($c >= 'A' && $c <= 'Z') || $c == '_')
  {
    return true;
  }
  return false;
}

function _HTMLEntity($c)
{
  switch($c)
  {
    case '<':
      return '&lt;';
    case '>':
      return '&gt;';
    case '&':
      return '&amp;';
    default:
      return $c;
  }
}

function highlight_delphi($source)
{
  $source = str_replace(array("\r\n", "\r"), array("\n", "\n"), $source).' ';           
  $retval = '';
  $code = &$source;
  $clen = strlen($code);
  $keywords = array(
'abstract' => true, 'and' => true, 'array' => true, 'as' => true, 'asm' => true, 'at' => true, 'begin' => true, 'case' => true,
'class' => true, 'const' => true, 'constructor' => true, 'contains' => true, 'destructor' => true,
'dispinterface' => true, 'div' => true, 'do' => true, 'downto' => true, 'else' => true, 'end' => true, 'except' => true,
'export' => true, 'exports' => true, 'external' => true, 'file' => true, 'finalization' => true, 'finally' => true,
'for' => true, 'function' => true, 'goto' => true, 'if' => true, 'implementation' => true, 'in' => true, 'inherited' => true,
'initialization' => true, 'inline' => true, 'interface' => true, 'is' => true, 'label' => true, 'library' => true,
'mod' => true, 'not' => true, 'object' => true, 'of' => true, 'on' => true, 'or' => true, 'overload' => true, 'override' => true,
'package' => true, 'packed' => true, 'private' => true, 'procedure' => true, 'program' => true, 'property' => true,
'protected' => true, 'public' => true, 'published' => true, 'raise' => true, 'record' => true, 'register' => true,
'repeat' => true, 'requires' => true, 'resourcestring' => true, 'set' => true, 'shl' => true, 'shr' => true, 'then' => true,
'threadvar' => true, 'to' => true, 'try' => true, 'type' => true, 'unit' => true, 'until' => true, 'uses' => true, 'var' => true,
'virtual' => true, 'while' => true, 'with' => true, 'xor' => true, 'assembler' => true, 'far' => true,
'near' => true, 'pascal' => true, 'register' => true, 'cdecl' => true, 'safecall' => true, 'stdcall' => true, 'varargs' => true);
  $types = array(
'ansichar' => true, 'ansistring' => true, 'bool' => true, 'boolean' => true, 'byte' => true, 'bytebool' => true, 'cardinal' => true, 'char' => true,
'comp' => true, 'currency' => true, 'dword' => true, 'double' => true, 'extended' => true, 'int64' => true, 'integer' => true, 'iunknown' => true,
'longbool' => true, 'longint' => true, 'longword' => true, 'pansichar' => true, 'pansistring' => true, 'pbool' => true, 'pboolean' => true, 'pbyte' => true,
'pbytearray' => true, 'pcardinal' => true, 'pchar' => true, 'pcomp' => true, 'pcurrency' => true, 'pdword' => true, 'pdate' => true, 'pdatetime' => true,
'pdouble' => true, 'pextended' => true, 'pint64' => true, 'pinteger' => true, 'plongint' => true, 'plongword' => true, 'pointer' => true, 'ppointer' => true,
'pshortint' => true, 'pshortstring' => true, 'psingle' => true, 'psmallint' => true, 'pstring' => true, 'phandle' => true, 'pvariant' => true, 'pword' => true,
'pwordarray' => true, 'pwordbool' => true, 'pwidechar' => true, 'pwidestring' => true, 'real' => true, 'real48' => true, 'shortint' => true, 'shortstring' => true,
'single' => true, 'smallint' => true, 'string' => true, 'tclass' => true, 'tdate' => true, 'tdatetime' => true, 'textfile' => true, 'thandle' => true,
'tobject' => true, 'ttime' => true, 'variant' => true, 'widechar' => true, 'widestring' => true, 'word' => true, 'wordbool' => true);
  $operators = array(
  '+' => true, '-' => true, '*' => true, '/' => true, '^' => true, '.' => true, '>' => true,
  '<' => true, '=' => true, ';' => true, ':' => true, ',' => true);
  $brackets = array(
  '(' => true, ')' => true, '[' => true, ']' => true);
   
  $token = ''; $hex = false;
  for($i = 0; $i < $clen; ++$i)
  {
    $char = $code[$i];
    if(_IsCharValid($char))
    {
      $token .= $char;
      if(_IsInArray(&$keywords, strtolower($token)))
      {
        if(_IsCharValid($code[$i + 1]))
        {
          continue;
        }
        $retval .= ('<span style="color: blue; font-weight: bold">' . $token . '</span>');
        $token = '';
      }
      if(_IsInArray(&$types, strtolower($token)))
      {
        if(_IsCharValid($code[$i + 1]))
        {
          continue;
        }
        $retval .= ('<span style="color: maroon">' . $token . '</span>');
        $token = '';
      }
      if(($token >= '0' && $token <= '9') || $hex)
      {
        $retval .= ('<span style="color: #800080">' . $token . '</span>');
        $token = '';
      }
    }
    else
    {
      $hex = false;
      if($char == '$')
      {
        $retval .= '<span style="color: #800080">$</span>';
        $hex = true;
        continue;
      }
      if($token != '')
      {
        $retval .= $token;
        $token = '';
      }
      if($char == '{' && $code[$i + 1] == '$')
      {
        $retval .= '<span style="color: #808080">';
        $j = $i;
        while($j < $clen && ($code[$j] != "}"))
        {
          $retval .= _HTMLEntity($code[$j]);
          ++$j;
        }
        if($j < $clen)
        {
          $retval .= '}';
        }
        $retval .= '</span>';
        $i = $j;
      }
      elseif($char == '\'')
      {
        $retval .= '<span style="color: red">';
        $j = $i + 1;
        $retval .= '\'';
        while($j < $clen && $code[$j] != '\'')
        {
          $retval .= _HTMLEntity($code[$j]);
          ++$j;
        }
        if($j < $clen)
        {
          $retval .= '\'';
        }
        $retval .= '</span>';
        $i = $j;
      }
      elseif($char == '/' && $code[$i + 1] == '/')
      {
        $retval .= '<span style="color: #808080">';
        $j = $i;
        while($j < $clen && $code[$j] != "\n")
        {
          $retval .= _HTMLEntity($code[$j]);
          ++$j;
        }
        $retval .= '</span>';
        $retval .= "\n";
        $i = $j;
      }
      elseif($char == '{' && $code[$i + 1] != '$')
      {
        $retval .= '<span style="color: #808080">';
        $j = $i;
        while($j < $clen && $code[$j] != '}')
        {
          $retval .= _HTMLEntity($code[$j]);
          ++$j;
        }
        if($j < $clen)
        {
          $retval .= '}';
        }        
        $retval .= '</span>';
        $i = $j;
      }
      else
      {
        if(_IsInArray(&$operators, &$char))
        {
          $retval .= '<span style="color: #300000">' . _HTMLEntity($char) . '</span>';
          continue;
        }
        elseif(_ISInArray(&$brackets, &$char))
        {
          $retval .= '<span style="color: #00BB00">' . _HTMLEntity($char) . '</span>';
          continue;
        }
        $retval .= $char;
      }
    }
  }
  return $retval; 
}

Może to nie jest wydajne, ale działa!
Teraz użycie: po prostu wystarczy wywołać funkcję highlight_delphi z kodem do pokolorowania jako pierwszy argument:

$source = 'unit bar;

interface

implementation

end.';

echo '<pre>' . highlight_delphi($source) . '</pre>';

13 komentarzy

Czy mi się wydaje, czy in_array() szuka liniowo? To co mam teraz daje O(1)...

no tak, ale po co w ogóle pisać array('begin'=>true, 'end'=>true) jak można array('begin', 'end') i wtedy in_array wystarczy

nie przygladalem sie kodowi, ale pierwsze co zauwazylem - po co ta funkcja _IsInArray, skoro jest standardowe in_array?

Teraz wszystko będzie działać, no ale to zupełnie inny kod jest :)

raczej o array_key_exists() powinno ci chodzić, ale to dlatego, że kod był pisany jak jeszcze tych funkcji nie znałem

a moze ktos ma gotowca? bo jakos u mnie nie chodzi nawet po porawieniu znakow.

Proponuję przerobić ten artykuł, bo znaki specialne mają błędy

"< i >< font color="000080" >// 1< br >< /font >< /i >");

"// 1
");

dlaczego mi się wydaje, że jak napisze // siema
to mi pokoloruje tylko // i wstawi 'i', a siema nie będzie pokolorowane :)

Można było zrobić ściślej :)

Aha... moga tu wystapic bledy, bo system tak parsuje kod html :[ Np. znak \ przed " trzeba wstawic.

vogel: to je funkcja php a nie delphi :P

Wow!! W SynEdicie jest to jakieś 10000 lini kodu więcej... :P