home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / turbopas / tptc17sc.arc / TPCEXPR.INC < prev    next >
Text File  |  1988-03-26  |  18KB  |  760 lines

  1.  
  2. (*
  3.  * TPTC - Turbo Pascal to C translator
  4.  *
  5.  * (C) 1988 Samuel H. Smith (rev. 13-Feb-88)
  6.  *
  7.  *)
  8.  
  9.  
  10. (*
  11.  * expression parser
  12.  *
  13.  *)
  14. function pterm: string; forward;
  15.  
  16. function iscall(var lv: string): boolean;
  17.    {see if the given lvalue is a function call or not}
  18. begin
  19.    iscall := lv[length(lv)] = ')';
  20. end;
  21.  
  22.  
  23. procedure make_pointer(var expr: string);
  24.    {convert the expression into a pointer constant, if possible}
  25. var
  26.    sym:  symptr;
  27. begin
  28.    
  29.    case(expr[1]) of
  30.       '*':
  31.       begin
  32.          delete(expr,1,1);
  33.          exit;
  34.       end;
  35.       
  36.       'a'..'z','A'..'Z','_':
  37.       begin         {pass pointer to strings/arrays}
  38.          sym := locatesym(expr);
  39.          if (sym <> nil) and ((sym^.symtype = s_string) or
  40.                               (sym^.suptype = ss_array)) then
  41.          begin
  42.             {null}
  43.          end
  44.          else
  45.          
  46.          if expr[length(expr)-1] = '(' then    {remove () from function calls}
  47.             dec(expr[0],2)
  48.             
  49.          else
  50.             expr := '&' + expr;
  51.       end;
  52.       
  53.    end;
  54.  
  55. end;
  56.  
  57.  
  58. function isnumber(var lv: string): boolean;
  59.   {see if the given value is a literal number}
  60. var
  61.    i: integer;
  62. begin
  63.    for i := 1 to length(lv) do
  64.       case lv[i] of
  65.          '0'..'9','.': ;
  66.          else
  67.             isnumber := false;
  68.             exit;
  69.       end;
  70.    isnumber := true;
  71. end;
  72.  
  73.  
  74. procedure subtract_base(var expr: string; base: integer);
  75.    {subtract the specified base from the given expression;
  76.     use constant folding if possible}
  77. begin
  78.    if base <> 0 then
  79.       if isnumber(expr) then
  80.          expr := itoa(atoi(expr) - base)
  81.       else
  82.       if base > 0 then
  83.          expr := expr + '-' + itoa(base)
  84.       else
  85.          expr := expr + '+' + itoa(-base);
  86. end;
  87.  
  88.  
  89. function exprtype: char;
  90.    {determine expression type and return the printf code for the type}
  91. var
  92.    xt:      char;
  93.  
  94. begin
  95.    case cexprtype of
  96.       s_char:    xt := 'c';
  97.       s_file:    xt := '@';
  98.       s_double:  xt := 'f';
  99.       s_string:  xt := 's';
  100.       s_bool:    xt := 'b';
  101.       s_int:     xt := 'd';
  102.       s_long:    xt := 'D'; { calling routine should convert to "ld" }
  103.       else       xt := '?';
  104.    end;
  105.  
  106.    exprtype := xt;
  107. end;
  108.  
  109.  
  110. function strtype(ty: char): boolean;
  111.    {see if the expression is a string data type or not}
  112. begin
  113.    case ty of
  114.       's','c':  strtype := true;
  115.       else      strtype := false;
  116.    end;
  117. end;
  118.  
  119.  
  120.  
  121. function psetof:  string;
  122.    {parse a literal set; returns the set literal translated into
  123.     the form: setof(.....)}
  124. var
  125.    ex: string;
  126.  
  127. begin
  128.    ex := 'setof(';
  129.    if tok[1] <> ']' then
  130.       ex := ex + pterm;
  131.  
  132.    while (tok = '..') or (tok[1] = ',') do
  133.    begin
  134.       if tok = '..' then       
  135.          ex := ex + ',__,'
  136.       else
  137.          ex := ex + ',';
  138.  
  139.       gettok;
  140.       ex := ex + pterm;
  141.    end;
  142.  
  143.    if ex[length(ex)] <> '(' then
  144.       ex := ex + ',';
  145.    ex := ex + '_E)';
  146.    psetof := ex;
  147. end;
  148.  
  149.  
  150. function pterm:   string;
  151.    {parse an expression term;  returns the translated expression term;
  152.     detects subexpressions, set literals and lvalues(variable names)}
  153. var
  154.    ex: string;
  155.    builtin: boolean;
  156.  
  157. begin
  158.    if debug_parse then write(' <term>');
  159.  
  160.    if (toktype = identifier) and (cursym <> nil) then
  161.       builtin := cursym^.suptype = ss_builtin
  162.    else
  163.       builtin := false;
  164.  
  165.    (* process pos(c,str) and pos(str,str) *)
  166.    if builtin and (tok = 'POS') then
  167.    begin
  168.       if debug_parse then write(' <pos>');
  169.       gettok;   {consume the keyword}
  170.       if tok[1] <> '(' then
  171.          syntax('"(" expected (pterm.pos)');
  172.       
  173.       gettok;   {consume the (}
  174.       ex := pexpr;
  175.       if exprtype{(ex)} = 'c' then
  176.          ex := 'cpos(' + ex
  177.       else
  178.          ex := 'spos(' + ex;
  179.  
  180.       gettok;   {consume the ,}
  181.       ex := ex + ',' + pexpr;
  182.       gettok;   {consume the )}
  183.       pterm := ex + ')';
  184.       cexprtype := s_int;
  185.    end
  186.    else
  187.  
  188.    (* process chr(n) *)
  189.    if builtin and (tok = 'CHR') then
  190.    begin
  191.       if debug_parse then write(' <chr>');
  192.       gettok;   {consume the keyword}
  193.       if tok[1] <> '(' then
  194.          syntax('"(" expected (pterm.chr)');
  195.       
  196.       gettok;   {consume the (}
  197.       ex := pexpr;
  198.       gettok;   {consume the )}
  199.  
  200.       if isnumber(ex) then
  201.          ex := numlit(atoi(ex))
  202.       else
  203.          ex := 'chr('+ex+')';
  204.  
  205.       pterm := ex;
  206.       cexprtype := s_char;
  207.    end
  208.    else
  209.  
  210.    (* translate NOT term into !term *)
  211.    if builtin and (tok = 'NOT') then
  212.    begin
  213.       if debug_parse then write(' <not>');
  214.       gettok;
  215.       pterm := '!' + pterm;
  216.       cexprtype := s_bool;
  217.    end
  218.    else
  219.  
  220.    (* process port/memory array references *)
  221.    if builtin and ((tok = 'PORT') or (tok = 'PORTW') or
  222.                    (tok = 'MEM')  or (tok = 'MEMW')) then
  223.    begin
  224.       if debug_parse then write(' <port>');
  225.       if tok = 'PORT'  then ex := 'inportb('    else
  226.       if tok = 'PORTW' then ex := 'inport('     else
  227.       if tok = 'MEM'   then ex := 'peekb('      else
  228.                             ex := 'peek(';
  229.  
  230.       gettok;     {consume the keyword}
  231.       gettok;     {consume the [ }
  232.  
  233.       repeat
  234.          ex := ex + pexpr;
  235.          if tok[1] = ':' then
  236.          begin
  237.             gettok;
  238.             ex := ex + ',';
  239.          end;
  240.       until (tok[1] = ']') or recovery;
  241.  
  242.       gettok;     {consume the ] }
  243.       pterm := ex + ')';
  244.       cexprtype := s_int;
  245.    end
  246.    else
  247.  
  248.    (* translate bitwise not (mt+) *)
  249.    if (tok[1] = '?') or (tok[1] = '~') or (tok[1] = '\') then
  250.    begin
  251.       if debug_parse then write(' <bitnot>');
  252.       gettok;
  253.       pterm := '!' + pterm;         {what is a bitwise NOT in c?}
  254.    end
  255.    else
  256.  
  257.    (* process unary minus *)
  258.    if tok = '-' then
  259.    begin
  260.       if debug_parse then write(' <unary>');
  261.       gettok;
  262.       pterm := '-' + pterm;
  263.    end
  264.    else
  265.  
  266.    (* translate address-of operator *)
  267.    if tok[1] = '@' then
  268.    begin
  269.       if debug_parse then write(' <ref>');
  270.       gettok;  {consume the '@'}
  271.       ex := plvalue;
  272.       make_pointer(ex);
  273.       pterm := ex;
  274.    end
  275.    else
  276.  
  277.    (* pass numbers *)
  278.    if toktype = number then
  279.    begin
  280.       if debug_parse then write(' <number>');
  281.       pterm := tok;
  282.       gettok;
  283.       cexprtype := s_int;
  284.    end
  285.    else
  286.  
  287.    (* pass strings *)
  288.    if toktype = strng then
  289.    begin
  290.       if debug_parse then write(' <string>');
  291.       pterm := tok;
  292.       gettok;
  293.       cexprtype := s_string;
  294.    end
  295.    else
  296.  
  297.    (* pass characters *)
  298.    if toktype = chars then
  299.    begin
  300.       if debug_parse then write(' <char>');
  301.       pterm := tok;
  302.       gettok;
  303.       cexprtype := s_char;
  304.    end
  305.    else
  306.  
  307.    (* pass sub expressions *)
  308.    if tok[1] = '(' then
  309.    begin
  310.       if debug_parse then write(' <subexp>');
  311.       gettok;
  312.       pterm := '(' + pexpr + ')';
  313.       gettok;
  314.    end
  315.    else
  316.  
  317.    (* translate literal sets *)
  318.    if tok[1] = '[' then
  319.    begin
  320.       if debug_parse then write(' <setlit>');
  321.       gettok;
  322.       pterm := psetof;
  323.       gettok;
  324.       cexprtype := s_struct;
  325.    end
  326.  
  327.    (* otherwise the term will be treated as an lvalue *)
  328.    else
  329.       pterm := plvalue;
  330. end;
  331.  
  332.  
  333. function pexpr: string;
  334.    {top level expression parser; parse and translate an expression and
  335.     return the translated expr}
  336. var
  337.    ex:       string;
  338.    ty:       char;
  339.    ex2:      string;
  340.    ty2:      char;
  341.  
  342.    procedure relop(newop: string40);
  343.    begin
  344.       if debug_parse then write(' <relop>');
  345.       gettok;        {consume the operator token}
  346.  
  347.       ex2 := pterm;  {get the second term}
  348.       ty2 := exprtype;
  349.  
  350.       {use strcmp if either param is a string}
  351.       if ty = 's' then
  352.       begin
  353.          if ty2 = 's' then
  354.             ex := 'strcmp(' + ex + ',' + ex2 + ') ' + newop + ' 0'
  355.          else
  356.          if ex2[1] = '''' then
  357.             ex := 'strcmp(' + ex + ',"' +
  358.                      copy(ex2,2,length(ex2)-2) + '") ' + newop + ' 0'
  359.          else
  360.             ex := 'strcmp(' + ex + ',ctos(' + ex2 + ')) ' + newop + ' 0'
  361.       end
  362.       else
  363.  
  364.       if ty = 'c' then
  365.       begin
  366.          if ty2 = 's' then
  367.             ex := 'strcmp(ctos(' + ex + '),' + ex2 + ') ' + newop + ' 0'
  368.          else
  369.             ex := ex + ' ' + newop + ' ' + ex2
  370.       end
  371.  
  372.       else
  373.          ex := ex + ' ' + newop + ' ' + ex2;
  374.  
  375.       cexprtype := s_bool;
  376.    end;
  377.  
  378.  
  379.    procedure addop;
  380.  
  381.       procedure add_scat;
  382.       var
  383.          p: integer;
  384.  
  385.       begin
  386.          {find end of control string}
  387.          p := 7;  {position of 'scat("%'}
  388.          while (ex[p] <> '"') or
  389.                ((ex[p] = '"') and (ex[p-1] = '\') and (ex[p-2] <> '\')) do
  390.             p := succ(p);
  391.          p := succ(p);
  392.  
  393.          {add literals to the control string if possible}
  394.          if (ex2[1] = '''') or (ex2[1] = '"') then
  395.             ex := copy(ex,1,p-2) + 
  396.                   copy(ex2,2,length(ex2)-2) +
  397.                   copy(ex,p-1,length(ex)-p+2)
  398.  
  399.          else {add a parameter to the control string}
  400.             ex := copy(ex,1,p-2) + '%' + ty2 +
  401.                   copy(ex,p-1,length(ex)-p+1) + ',' + ex2 + ')';
  402.       end;
  403.  
  404.    begin
  405.       if debug_parse then write(' <addop>');
  406.       gettok;        {consume the operator token}
  407.  
  408.       ex2 := pterm;  {get the second term}
  409.       ty2 := exprtype;
  410.  
  411. (* writeln('ex{',ex,'}',ty,' ex2{',ex2,'}',ty2); *)
  412.  
  413.       {continue adding string params to scat control string}
  414.       if (ex[5] = '(') and (copy(ex,1,4) = 'scat') then
  415.          add_scat
  416.       else
  417.  
  418.       {start new scat call if any par is a string}
  419.       if strtype(ty) or strtype(ty2) then
  420.       begin
  421.          if (ex[1] = '''') or (ex[1] = '"') then
  422.             ex := 'scat("' + copy(ex,2,length(ex)-2) + '")'
  423.          else
  424.             ex := 'scat("%' + ty + '",' + ex + ')';
  425.          add_scat;
  426.       end
  427.       else
  428.          ex := ex + ' + ' + ex2;
  429.  
  430. (* writeln('ex=',ex); *)
  431.    end;
  432.  
  433.    procedure mulop(newop: string40);
  434.    begin
  435.       if debug_parse then write(' <mulop>');
  436.       gettok;        {consume the operator token}
  437.  
  438.       ex2 := pterm;  {get the second term}
  439.       ex := ex + ' ' + newop + ' ' + ex2;
  440.    end;
  441.  
  442.    procedure andop(newop: char);
  443.    begin
  444.       if debug_parse then write(' <andop>');
  445.       gettok;        {consume the operator token}
  446.  
  447.       ex2 := pterm;  {get the second term}
  448.       ty2 := exprtype;
  449.  
  450.       {boolean and/or?}
  451.       if (ty = 'b') or (ty2 = 'b') then
  452.       begin
  453.          ex := ex + ' ' + newop + newop + ' ' + ex2;
  454.          cexprtype := s_bool;
  455.       end
  456.       else  {otherwise bitwise}
  457.          ex := ex + ' ' + newop + ' ' + ex2;
  458.    end;
  459.  
  460.  
  461. begin
  462.    if debug_parse then write(' <expr>');
  463.    ex := pterm;
  464.    ty := exprtype;
  465.  
  466.    while true do
  467.    begin
  468.       (* process operators *)
  469.            if tok    = '>='  then relop(tok)
  470.       else if tok    = '<='  then relop(tok)
  471.       else if tok    = '<>'  then relop('!=')
  472.       else if tok[1] = '>'   then relop(tok)
  473.       else if tok[1] = '<'   then relop(tok)
  474.       else if tok[1] = '='   then relop('==')
  475.       else if tok[1] = '+'   then addop
  476.       else if tok[1] = '-'   then mulop(tok)
  477.       else if tok[1] = '*'   then mulop(tok)
  478.       else if tok[1] = '/'   then mulop(tok)
  479.       else if tok[1] = '&'   then mulop(tok)  {mt+}
  480.       else if tok[1] = '!'   then mulop('|')  {mt+}
  481.       else if tok[1] = '|'   then mulop('|')  {mt+}
  482.       else if tok    = 'DIV' then mulop('/')
  483.       else if tok    = 'MOD' then mulop('%')
  484.       else if tok    = 'SHR' then mulop('>>')
  485.       else if tok    = 'SHL' then mulop('<<')
  486.       else if tok    = 'XOR' then mulop('^')
  487.       else if tok    = 'AND' then andop('&')
  488.       else if tok    = 'OR'  then andop('|')
  489.       else
  490.  
  491.       (* translate the expr IN set operator *)
  492.       if tok = 'IN'  then
  493.       begin
  494.          gettok;
  495.          ex := 'inset('+ex+',' + pterm + ')';
  496.       end
  497.       else
  498.  
  499.       (* ran out of legal expression operators; return what we found *)
  500.       begin
  501.          pexpr := ex;
  502.          exit;
  503.       end;
  504.    end;
  505.  
  506. end;
  507.  
  508.  
  509. function plvalue: string;
  510.    {parse and translate an lvalue specification and return the translated
  511.     lvalue as a string}
  512.  
  513. var
  514.    lv:       string;
  515.    expr:     string;
  516.    funcid:   string40;
  517.    pref:     string40;
  518.    idok:     boolean;
  519.    sym:      symptr;
  520.    func:     symptr;
  521.    btype:    symtypes;
  522.    cstype:   supertypes;
  523.    bstype:   supertypes;
  524.    pvars:    integer;
  525.    cbase:    integer;
  526.    bbase:    integer;
  527.       
  528. begin
  529.    if debug_parse then write(' <lvalue>');
  530.    plvalue := 'lvalue';
  531.  
  532. (* lvalues must begin with an identifier in pascal *)
  533.    if toktype <> identifier then
  534.    begin
  535.       syntax('Identifier expected (plvalue)');
  536.       exit;
  537.    end;
  538.  
  539. (* assign initial part of the lvalue *)
  540.    idok := false;
  541.    pref := '';
  542.    lv := ltok;
  543.    funcid := tok;
  544.    bstype := ss_scalar;
  545.    bbase := 0;
  546.    cbase := 0;
  547.  
  548.    sym := cursym;
  549.    if sym <> nil then
  550.    begin
  551.       cstype := sym^.suptype;
  552.       cbase := sym^.base;
  553.       cexprtype := sym^.symtype;
  554.       lv := sym^.repid;          {use replacement identifier}
  555.  
  556.       {dereference VAR paremter pointers}
  557.       if sym^.parcount = -2 then
  558.       begin
  559.          if debug_parse then write(' <var.deref>');
  560.          pref := '*';
  561.       end;
  562.       
  563.       {prefix with pointer if this is a member identifier and a with
  564.        is in effect}
  565.       if (sym^.parcount < 0) and (sym^.pvar > 0) and (withlevel > 0) then
  566.       begin
  567.          if debug_parse then write(' <with.deref>');
  568.          pref := 'with'+itoa(withlevel)+'->';
  569.       end;
  570.       
  571.    end;
  572.    
  573.  
  574. (* process a list of qualifiers and modifiers *)
  575.    gettok;
  576.  
  577.    repeat
  578.       if toktype = identifier then
  579.       begin
  580.  
  581.          if cursym <> nil then               {find record member types}
  582.          begin
  583.             sym := cursym;
  584.             cstype := sym^.suptype;
  585.             cbase := sym^.base;
  586.             cexprtype := sym^.symtype;
  587.             ltok := sym^.repid;          {use replacement identifier}
  588.          end;
  589.          
  590.       end;
  591.       
  592.       (* process identifiers (variable or field names) *)
  593.       if idok and (toktype = identifier) then
  594.       begin
  595.          if debug_parse then write(' <ident>');
  596.          lv := lv + ltok;
  597.          gettok;
  598.          idok := false;
  599.       end
  600.       else
  601.  
  602.       (* pointers *)
  603.       if tok = '^' then
  604.       begin
  605.          if debug_parse then write(' <deref>');
  606.          pref := '*' + pref;
  607.          gettok;
  608.       end
  609.       else
  610.  
  611.       (* pointer subscripts *)
  612.       if tok = '^[' then
  613.       begin
  614.          if debug_parse then write(' <ptr.subs>');
  615.          lv := lv + '[';
  616.          gettok;
  617.  
  618.          while tok <> ']' do
  619.          begin
  620.             lv := lv + pexpr;
  621.             if tok = ',' then
  622.             begin
  623.                lv := lv + '][';
  624.                gettok;
  625.             end;
  626.          end;
  627.  
  628.          lv := lv + ']';
  629.          gettok;
  630.       end
  631.       else
  632.  
  633.       (* pointer members *)
  634.       if tok = '^.' then
  635.       begin
  636.          if debug_parse then write(' <ptr.deref>');
  637.          lv := lv + '->';
  638.          gettok;
  639.          idok := true;
  640.       end
  641.       else
  642.  
  643.       (* record members *)
  644.       if tok = '.' then
  645.       begin
  646.          if debug_parse then write(' <member>');
  647.          if pref = '*' then     {translate *id. into id->}
  648.          begin
  649.             pref := '';
  650.             lv := lv + '->';
  651.          end
  652.          else
  653.             lv := lv + '.';
  654.          idok := true;
  655.          gettok;
  656.       end
  657.       else
  658.  
  659.       (* subscripts *)
  660.       if tok[1] = '[' then
  661.       begin
  662.          if debug_parse then write(' <subs>');
  663.          btype := cexprtype;
  664.          bstype := cstype;
  665.          bbase := cbase;
  666.  
  667.          if copy(pref,1,1) = '*' then
  668.             pref := '';       {replace '*id[' with 'id['}
  669.  
  670.          lv := lv + '[';
  671.          gettok;
  672.  
  673.          repeat
  674.             expr := pexpr;
  675.  
  676.             if tok[1] = ',' then
  677.             begin
  678.                lv := lv + expr + '][';
  679.                gettok;
  680.                bstype := ss_scalar;
  681.             end;
  682.          until tok[1] = ']';
  683.  
  684.          subtract_base(expr,bbase);
  685.          lv := lv + expr + ']';
  686.  
  687.          if (btype = s_string) and (bstype <> ss_array) then
  688.          begin
  689.             btype := s_char;
  690.             ltok := lv;
  691.             if expr = '-1' then
  692.                warning('Dynamic length reference');
  693.          end;
  694.  
  695.          cexprtype := btype;
  696.          cstype := ss_scalar;
  697.          cbase := 0;
  698.          gettok;
  699.       end
  700.       else
  701.  
  702.       (* function calls *)
  703.       if tok[1] = '(' then
  704.       begin
  705.          if debug_parse then write(' <func>');
  706.          func := locatesym(funcid);
  707.          pvars := 0;
  708.          if func <> nil then
  709.          begin
  710.             pvars := func^.pvar;          {determine return type}
  711.             cexprtype := func^.symtype;
  712.          end;
  713.             
  714.          btype := cexprtype;
  715.          lv := lv + '(';
  716.          gettok;
  717.  
  718.          while tok[1] <> ')' do
  719.          begin
  720.             expr := pexpr;
  721.             if (pvars and 1) = 1 then     {prefix VAR paremeters}
  722.                make_pointer(expr);
  723.  
  724.             lv := lv + expr;
  725.             pvars := pvars shr 1;
  726.  
  727.             if (tok[1] = ',') or (tok = ':') then
  728.             begin
  729.                lv := lv + ',';
  730.                gettok;
  731.             end;
  732.          end;
  733.  
  734.          lv := lv + ')';
  735.          gettok;
  736.          cexprtype := btype;
  737.       end
  738.       else
  739.  
  740. (* otherwise just return what was found so far *)
  741.       begin
  742.  
  743.          (* add dummy param list to function calls where the proc
  744.             expects no parameters *)
  745.          if sym <> nil then
  746.          begin
  747.             if (not iscall(lv)) and (sym^.parcount >= 0) then
  748.                lv := lv + '()';
  749.          end;
  750.  
  751.          plvalue := pref + lv;
  752.          exit;
  753.       end;
  754.  
  755.    until recovery;
  756.  
  757.    plvalue := pref + lv;
  758. end;
  759.  
  760.