mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-16 13:19:12 +02:00
compiler: implement preprocessor expressions (fixes mantis #0010671)
- move operator_levels to topens.pas - it is used from 2 units now - implement pexpr like sub_expr for preprocessor expressions - implement +,-,*,/ expressions for the moment * move OR, AND, IN implemenetation to the new logic git-svn-id: trunk@25465 -
This commit is contained in:
parent
6eba4226b6
commit
038b7746fb
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -12766,6 +12766,7 @@ tests/webtbs/tw10641.pp svneol=native#text/plain
|
|||||||
tests/webtbs/tw1066a.pp svneol=native#text/plain
|
tests/webtbs/tw1066a.pp svneol=native#text/plain
|
||||||
tests/webtbs/tw1066b.pp svneol=native#text/plain
|
tests/webtbs/tw1066b.pp svneol=native#text/plain
|
||||||
tests/webtbs/tw10670.pp svneol=native#text/pascal
|
tests/webtbs/tw10670.pp svneol=native#text/pascal
|
||||||
|
tests/webtbs/tw10671.pp svneol=native#text/pascal
|
||||||
tests/webtbs/tw1068.pp svneol=native#text/plain
|
tests/webtbs/tw1068.pp svneol=native#text/plain
|
||||||
tests/webtbs/tw10681.pp svneol=native#text/plain
|
tests/webtbs/tw10681.pp svneol=native#text/plain
|
||||||
tests/webtbs/tw10684.pp svneol=native#text/plain
|
tests/webtbs/tw10684.pp svneol=native#text/plain
|
||||||
|
@ -73,14 +73,6 @@ implementation
|
|||||||
pbase,pinline,ptype,pgenutil,procinfo,cpuinfo
|
pbase,pinline,ptype,pgenutil,procinfo,cpuinfo
|
||||||
;
|
;
|
||||||
|
|
||||||
{ sub_expr(opmultiply) is need to get -1 ** 4 to be
|
|
||||||
read as - (1**4) and not (-1)**4 PM }
|
|
||||||
type
|
|
||||||
Toperator_precedence=(opcompare,opaddition,opmultiply,oppower);
|
|
||||||
|
|
||||||
const
|
|
||||||
highest_precedence = oppower;
|
|
||||||
|
|
||||||
function sub_expr(pred_level:Toperator_precedence;accept_equal,typeonly:boolean;factornode:tnode):tnode;forward;
|
function sub_expr(pred_level:Toperator_precedence;accept_equal,typeonly:boolean;factornode:tnode):tnode;forward;
|
||||||
|
|
||||||
const
|
const
|
||||||
@ -3392,15 +3384,6 @@ implementation
|
|||||||
{****************************************************************************
|
{****************************************************************************
|
||||||
Sub_Expr
|
Sub_Expr
|
||||||
****************************************************************************}
|
****************************************************************************}
|
||||||
const
|
|
||||||
{ Warning these stay be ordered !! }
|
|
||||||
operator_levels:array[Toperator_precedence] of set of NOTOKEN..last_operator=
|
|
||||||
([_LT,_LTE,_GT,_GTE,_EQ,_NE,_OP_IN],
|
|
||||||
[_PLUS,_MINUS,_OP_OR,_PIPE,_OP_XOR],
|
|
||||||
[_CARET,_SYMDIF,_STARSTAR,_STAR,_SLASH,
|
|
||||||
_OP_AS,_OP_IS,_OP_AND,_AMPERSAND,_OP_DIV,_OP_MOD,_OP_SHL,_OP_SHR],
|
|
||||||
[_STARSTAR] );
|
|
||||||
|
|
||||||
function sub_expr(pred_level:Toperator_precedence;accept_equal,typeonly:boolean;factornode:tnode):tnode;
|
function sub_expr(pred_level:Toperator_precedence;accept_equal,typeonly:boolean;factornode:tnode):tnode;
|
||||||
{Reads a subexpression while the operators are of the current precedence
|
{Reads a subexpression while the operators are of the current precedence
|
||||||
level, or any higher level. Replaces the old term, simpl_expr and
|
level, or any higher level. Replaces the old term, simpl_expr and
|
||||||
|
@ -1014,7 +1014,7 @@ type
|
|||||||
lvs,rvs: string;
|
lvs,rvs: string;
|
||||||
begin
|
begin
|
||||||
case op of
|
case op of
|
||||||
_IN:
|
_OP_IN:
|
||||||
begin
|
begin
|
||||||
if not is_set(v.def) then
|
if not is_set(v.def) then
|
||||||
begin
|
begin
|
||||||
@ -1231,9 +1231,12 @@ type
|
|||||||
inherited destroy;
|
inherited destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function parse_compiler_expr:texprvalue;
|
const
|
||||||
|
preproc_operators=[_EQ,_NE,_LT,_GT,_LTE,_GTE,_MINUS,_PLUS,_STAR,_SLASH,_OP_IN,_OP_AND,_OP_OR];
|
||||||
|
|
||||||
function read_expr(eval:Boolean): texprvalue; forward;
|
function preproc_comp_expr:texprvalue;
|
||||||
|
|
||||||
|
function preproc_sub_expr(pred_level:Toperator_precedence;eval:Boolean):texprvalue; forward;
|
||||||
|
|
||||||
procedure preproc_consume(t:ttoken);
|
procedure preproc_consume(t:ttoken);
|
||||||
begin
|
begin
|
||||||
@ -1472,7 +1475,7 @@ type
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function read_factor(eval: Boolean):texprvalue;
|
function preproc_factor(eval: Boolean):texprvalue;
|
||||||
var
|
var
|
||||||
hs,countstr,storedpattern: string;
|
hs,countstr,storedpattern: string;
|
||||||
mac: tmacro;
|
mac: tmacro;
|
||||||
@ -1768,7 +1771,7 @@ type
|
|||||||
if current_scanner.preproc_pattern='NOT' then
|
if current_scanner.preproc_pattern='NOT' then
|
||||||
begin
|
begin
|
||||||
preproc_consume(_ID);
|
preproc_consume(_ID);
|
||||||
exprvalue:=read_factor(eval);
|
exprvalue:=preproc_factor(eval);
|
||||||
if eval then
|
if eval then
|
||||||
result:=exprvalue.evaluate(nil,_OP_NOT)
|
result:=exprvalue.evaluate(nil,_OP_NOT)
|
||||||
else
|
else
|
||||||
@ -1818,7 +1821,7 @@ type
|
|||||||
else if current_scanner.preproc_token =_LKLAMMER then
|
else if current_scanner.preproc_token =_LKLAMMER then
|
||||||
begin
|
begin
|
||||||
preproc_consume(_LKLAMMER);
|
preproc_consume(_LKLAMMER);
|
||||||
result:=read_expr(eval);
|
result:=preproc_sub_expr(opcompare,true);
|
||||||
preproc_consume(_RKLAMMER);
|
preproc_consume(_RKLAMMER);
|
||||||
end
|
end
|
||||||
else if current_scanner.preproc_token = _LECKKLAMMER then
|
else if current_scanner.preproc_token = _LECKKLAMMER then
|
||||||
@ -1827,7 +1830,7 @@ type
|
|||||||
ns:=[];
|
ns:=[];
|
||||||
while current_scanner.preproc_token in [_ID,_INTCONST] do
|
while current_scanner.preproc_token in [_ID,_INTCONST] do
|
||||||
begin
|
begin
|
||||||
exprvalue:=read_factor(eval);
|
exprvalue:=preproc_factor(eval);
|
||||||
include(ns,exprvalue.asInt);
|
include(ns,exprvalue.asInt);
|
||||||
if current_scanner.preproc_token = _COMMA then
|
if current_scanner.preproc_token = _COMMA then
|
||||||
preproc_consume(_COMMA);
|
preproc_consume(_COMMA);
|
||||||
@ -1862,101 +1865,51 @@ type
|
|||||||
result:=texprvalue.create_error;
|
result:=texprvalue.create_error;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function read_term(eval: Boolean):texprvalue;
|
function preproc_sub_expr(pred_level:Toperator_precedence;eval:Boolean): texprvalue;
|
||||||
var
|
var
|
||||||
hs1,hs2: texprvalue;
|
hs1,hs2: texprvalue;
|
||||||
|
op: ttoken;
|
||||||
begin
|
begin
|
||||||
result:=read_factor(eval);
|
if pred_level=highest_precedence then
|
||||||
|
result:=preproc_factor(eval)
|
||||||
|
else
|
||||||
|
result:=preproc_sub_expr(succ(pred_level),eval);
|
||||||
|
|
||||||
repeat
|
repeat
|
||||||
if (current_scanner.preproc_token<>_ID) then
|
op:=current_scanner.preproc_token;
|
||||||
break;
|
if (op in preproc_operators) and
|
||||||
if current_scanner.preproc_pattern<>'AND' then
|
(op in operator_levels[pred_level]) then
|
||||||
break;
|
|
||||||
|
|
||||||
preproc_consume(_ID);
|
|
||||||
hs2:=read_factor(eval);
|
|
||||||
|
|
||||||
if eval then
|
|
||||||
begin
|
|
||||||
hs1:=result;
|
|
||||||
result:=hs1.evaluate(hs2,_OP_AND);
|
|
||||||
hs1.free;
|
|
||||||
hs2.free;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
hs2.free;
|
|
||||||
until false;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
function read_simple_expr(eval: Boolean): texprvalue;
|
|
||||||
var
|
|
||||||
hs1,hs2: texprvalue;
|
|
||||||
begin
|
|
||||||
result:=read_term(eval);
|
|
||||||
repeat
|
|
||||||
if (current_scanner.preproc_token<>_ID) then
|
|
||||||
break;
|
|
||||||
if current_scanner.preproc_pattern<>'OR' then
|
|
||||||
break;
|
|
||||||
|
|
||||||
preproc_consume(_ID);
|
|
||||||
hs2:=read_term(eval);
|
|
||||||
|
|
||||||
if eval then
|
|
||||||
begin
|
|
||||||
hs1:=result;
|
|
||||||
result:=hs1.evaluate(hs2,_OP_OR);
|
|
||||||
hs1.free;
|
|
||||||
hs2.free;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
hs2.free;
|
|
||||||
until false;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function read_expr(eval:Boolean): texprvalue;
|
|
||||||
var
|
|
||||||
hs1,hs2: texprvalue;
|
|
||||||
op: ttoken;
|
|
||||||
begin
|
|
||||||
hs1:=read_simple_expr(eval);
|
|
||||||
op:=current_scanner.preproc_token;
|
|
||||||
if (op = _ID) and (current_scanner.preproc_pattern = 'IN') then
|
|
||||||
op := _IN;
|
|
||||||
if not (op in [_IN,_EQ,_NE,_LT,_GT,_LTE,_GTE]) then
|
|
||||||
begin
|
begin
|
||||||
result:=hs1;
|
hs1:=result;
|
||||||
exit;
|
preproc_consume(op);
|
||||||
end;
|
if pred_level=highest_precedence then
|
||||||
|
hs2:=preproc_factor(eval)
|
||||||
if (op = _IN) then
|
else
|
||||||
preproc_consume(_ID)
|
hs2:=preproc_sub_expr(succ(pred_level),eval);
|
||||||
|
if eval then
|
||||||
|
result:=hs1.evaluate(hs2,op)
|
||||||
|
else
|
||||||
|
result:=texprvalue.create_bool(false); {Just to have something}
|
||||||
|
hs1.free;
|
||||||
|
hs2.free;
|
||||||
|
end
|
||||||
else
|
else
|
||||||
preproc_consume(op);
|
break;
|
||||||
hs2:=read_simple_expr(eval);
|
until false;
|
||||||
|
|
||||||
if eval then
|
|
||||||
result:=hs1.evaluate(hs2,op)
|
|
||||||
else
|
|
||||||
result:=texprvalue.create_bool(false); {Just to have something}
|
|
||||||
|
|
||||||
hs1.free;
|
|
||||||
hs2.free;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
current_scanner.skipspace;
|
current_scanner.skipspace;
|
||||||
{ start preproc expression scanner }
|
{ start preproc expression scanner }
|
||||||
current_scanner.preproc_token:=current_scanner.readpreproc;
|
current_scanner.preproc_token:=current_scanner.readpreproc;
|
||||||
parse_compiler_expr:=read_expr(true);
|
preproc_comp_expr:=preproc_sub_expr(opcompare,true);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function boolean_compile_time_expr(var valuedescr: string): Boolean;
|
function boolean_compile_time_expr(var valuedescr: string): Boolean;
|
||||||
var
|
var
|
||||||
hs: texprvalue;
|
hs: texprvalue;
|
||||||
begin
|
begin
|
||||||
hs:=parse_compiler_expr;
|
hs:=preproc_comp_expr;
|
||||||
if is_boolean(hs.def) then
|
if is_boolean(hs.def) then
|
||||||
result:=hs.asBool
|
result:=hs.asBool
|
||||||
else
|
else
|
||||||
@ -2132,7 +2085,7 @@ type
|
|||||||
if c='=' then
|
if c='=' then
|
||||||
begin
|
begin
|
||||||
current_scanner.readchar;
|
current_scanner.readchar;
|
||||||
exprvalue:=parse_compiler_expr;
|
exprvalue:=preproc_comp_expr;
|
||||||
if not is_boolean(exprvalue.def) and
|
if not is_boolean(exprvalue.def) and
|
||||||
not is_integer(exprvalue.def) then
|
not is_integer(exprvalue.def) then
|
||||||
exprvalue.error('Boolean, Integer', 'SETC');
|
exprvalue.error('Boolean, Integer', 'SETC');
|
||||||
@ -5082,6 +5035,9 @@ exit_label:
|
|||||||
|
|
||||||
|
|
||||||
function tscannerfile.readpreproc:ttoken;
|
function tscannerfile.readpreproc:ttoken;
|
||||||
|
var
|
||||||
|
low,high,mid: longint;
|
||||||
|
optoken: ttoken;
|
||||||
begin
|
begin
|
||||||
skipspace;
|
skipspace;
|
||||||
case c of
|
case c of
|
||||||
@ -5089,8 +5045,34 @@ exit_label:
|
|||||||
'A'..'Z',
|
'A'..'Z',
|
||||||
'a'..'z' :
|
'a'..'z' :
|
||||||
begin
|
begin
|
||||||
current_scanner.preproc_pattern:=readid;
|
readstring;
|
||||||
readpreproc:=_ID;
|
optoken:=_ID;
|
||||||
|
if (pattern[1]<>'_') and (length(pattern) in [tokenlenmin..tokenlenmax]) then
|
||||||
|
begin
|
||||||
|
low:=ord(tokenidx^[length(pattern),pattern[1]].first);
|
||||||
|
high:=ord(tokenidx^[length(pattern),pattern[1]].last);
|
||||||
|
while low<high do
|
||||||
|
begin
|
||||||
|
mid:=(high+low+1) shr 1;
|
||||||
|
if pattern<tokeninfo^[ttoken(mid)].str then
|
||||||
|
high:=mid-1
|
||||||
|
else
|
||||||
|
low:=mid;
|
||||||
|
end;
|
||||||
|
with tokeninfo^[ttoken(high)] do
|
||||||
|
if pattern=str then
|
||||||
|
begin
|
||||||
|
if (keyword*current_settings.modeswitches)<>[] then
|
||||||
|
if op=NOTOKEN then
|
||||||
|
optoken:=ttoken(high)
|
||||||
|
else
|
||||||
|
optoken:=op;
|
||||||
|
end;
|
||||||
|
if not (optoken in preproc_operators) then
|
||||||
|
optoken:=_ID;
|
||||||
|
end;
|
||||||
|
current_scanner.preproc_pattern:=pattern;
|
||||||
|
readpreproc:=optoken;
|
||||||
end;
|
end;
|
||||||
'0'..'9' :
|
'0'..'9' :
|
||||||
begin
|
begin
|
||||||
|
@ -295,6 +295,15 @@ type
|
|||||||
_GREATERTHANOREQUAL
|
_GREATERTHANOREQUAL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
{ sub_expr(opmultiply) is need to get -1 ** 4 to be
|
||||||
|
read as - (1**4) and not (-1)**4 PM }
|
||||||
|
toperator_precedence=(
|
||||||
|
opcompare,
|
||||||
|
opaddition,
|
||||||
|
opmultiply,
|
||||||
|
oppower
|
||||||
|
);
|
||||||
|
|
||||||
const
|
const
|
||||||
tokenlenmin = 1;
|
tokenlenmin = 1;
|
||||||
tokenlenmax = 18;
|
tokenlenmax = 18;
|
||||||
@ -307,6 +316,16 @@ const
|
|||||||
last_overloaded = _OP_DEC;
|
last_overloaded = _OP_DEC;
|
||||||
last_operator = _GENERICSPECIALTOKEN;
|
last_operator = _GENERICSPECIALTOKEN;
|
||||||
|
|
||||||
|
highest_precedence = oppower;
|
||||||
|
|
||||||
|
{ Warning these stay be ordered !! }
|
||||||
|
operator_levels:array[Toperator_precedence] of set of NOTOKEN..last_operator=
|
||||||
|
([_LT,_LTE,_GT,_GTE,_EQ,_NE,_OP_IN],
|
||||||
|
[_PLUS,_MINUS,_OP_OR,_PIPE,_OP_XOR],
|
||||||
|
[_CARET,_SYMDIF,_STARSTAR,_STAR,_SLASH,
|
||||||
|
_OP_AS,_OP_IS,_OP_AND,_AMPERSAND,_OP_DIV,_OP_MOD,_OP_SHL,_OP_SHR],
|
||||||
|
[_STARSTAR] );
|
||||||
|
|
||||||
type
|
type
|
||||||
tokenrec=record
|
tokenrec=record
|
||||||
str : string[tokenlenmax];
|
str : string[tokenlenmax];
|
||||||
|
25
tests/webtbs/tw10671.pp
Normal file
25
tests/webtbs/tw10671.pp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
program tw10671;
|
||||||
|
|
||||||
|
{$IFDEF FPC}
|
||||||
|
{$MODE Delphi}
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
uses
|
||||||
|
SysUtils;
|
||||||
|
|
||||||
|
const
|
||||||
|
VER_MAJ = 10000;
|
||||||
|
VER_MIN = 100;
|
||||||
|
VER_REL = 1;
|
||||||
|
|
||||||
|
const
|
||||||
|
MY_VERSION = 020200;
|
||||||
|
|
||||||
|
{$IF MY_VERSION >= ((VER_MAJ*2) + (VER_MIN*1) + (VER_REL*0))}
|
||||||
|
{$MESSAGE Info 'Arithmetic in compile-time expressions works!'}
|
||||||
|
{$ELSE}
|
||||||
|
{$Message Error 'Arithmetic in compile-time expressions fails!'}
|
||||||
|
{$IFEND}
|
||||||
|
|
||||||
|
begin
|
||||||
|
end.
|
Loading…
Reference in New Issue
Block a user