Hi,

At Wed, 4 Feb 2004 15:23:10 +0900,
Jamis Buck wrote in [ruby-talk:91521]:
> In general, you want a parser that extracts everything between BEGIN and 
> END, but there are a few cases where you want to treat the word 
> 'special' as the end instead, and then ignore everything until the next 
> BEGIN.
> 
> while line = file.gets
>   if in line=~/BEGIN/ .. line=~/END/ => state
>     state.set_state( line =~ /special/ )
>     if state.get_state
>       # process line
>     end
>   end
> end

Will set_state turn the state true, or false?  Seeing the next
line, set_state(true) makes get_state to return false...

> Like I said, it's pretty contrived, and would be better solved by 
> choosing smarter guard conditions. However, it demonstrates a situation 
> where exposing an interface for manipulating a flip-flop's state may be 
> useful.

Rather, what about binding a flip-flop operator to a local
variable?

$ ./ruby -e 'while l = gets; if in /BEGIN/=~l .. /END/=~l => last; p [l, last]; last = /special/!~l end; end'
xx
BEGIN
["BEGIN\n", true]
xxx
["xxx\n", true]
special
["special\n", true]
dsfa
ffdf
END
xxx
BEGIN
["BEGIN\n", true]
xxx
["xxx\n", true]
END
["END\n", false]


Index: node.h =================================================================== RCS file: /cvs/ruby/src/ruby/node.h,v retrieving revision 1.52 diff -u -2 -p -d -r1.52 node.h --- node.h 22 Jan 2004 08:31:33 -0000 1.52 +++ node.h 4 Feb 2004 06:37:48 -0000 @@ -327,4 +327,6 @@ typedef struct RNode { #define NEW_DOT2(b,e) NEW_NODE(NODE_DOT2,b,e,0) #define NEW_DOT3(b,e) NEW_NODE(NODE_DOT3,b,e,0) +#define NEW_FLIP2(b,e,v) NEW_NODE(NODE_FLIP2,b,e,v) +#define NEW_FLIP3(b,e,v) NEW_NODE(NODE_FLIP3,b,e,v) #define NEW_ATTRSET(a) NEW_NODE(NODE_ATTRSET,a,0,0) #define NEW_SELF() NEW_NODE(NODE_SELF,0,0,0) Index: parse.y =================================================================== RCS file: /cvs/ruby/src/ruby/parse.y,v retrieving revision 1.315 diff -u -2 -p -d -r1.315 parse.y --- parse.y 3 Feb 2004 02:23:20 -0000 1.315 +++ parse.y 4 Feb 2004 06:49:09 -0000 @@ -266,5 +266,5 @@ static void top_local_setup(); %type <id> fitem variable sym symbol operation operation2 operation3 %type <id> cname fname op f_rest_arg -%type <num> f_norm_arg f_arg +%type <num> f_norm_arg f_arg flip_var %token tUPLUS /* unary+ */ %token tUMINUS /* unary- */ @@ -279,4 +279,5 @@ static void top_local_setup(); %token tMATCH tNMATCH /* =~ and !~ */ %token tDOT2 tDOT3 /* .. and ... */ +%token tFLIP2 tFLIP3 /* ~~ and ~~~ */ %token tAREF tASET /* [] and []= */ %token tLSHFT tRSHFT /* << and >> */ @@ -311,4 +312,5 @@ static void top_local_setup(); %right '?' ':' %nonassoc tDOT2 tDOT3 +%nonassoc tFLIP2 tFLIP3 %left tOROP %left tANDOP @@ -602,4 +604,16 @@ stmt : kALIAS fitem {lex_state = EXPR_F ; +flip_var : tASSOC tIDENTIFIER + { + if (!is_local_id($2)) + yyerror("flip-flop variable must be local variable"); + $$ = local_cnt($2); + } + | none + { + $$ = local_append(internal_id()); + } + ; + expr : command_call | expr kAND expr @@ -619,4 +633,16 @@ expr : command_call $$ = NEW_NOT(cond($2)); } + | kIN arg tDOT2 arg flip_var + { + value_expr($2); + value_expr($4); + $$ = NEW_FLIP2($2, $4, $5); + } + | kIN arg tDOT3 arg flip_var + { + value_expr($2); + value_expr($4); + $$ = NEW_FLIP3($2, $4, $5); + } | arg ; @@ -1069,4 +1095,16 @@ arg : lhs '=' arg $$ = NEW_DOT3($1, $3); } + | arg tFLIP2 arg + { + value_expr($1); + value_expr($3); + $$ = NEW_FLIP2($1, $3, local_append(internal_id())); + } + | arg tFLIP3 arg + { + value_expr($1); + value_expr($3); + $$ = NEW_FLIP3($1, $3, local_append(internal_id())); + } | arg '+' arg { @@ -4038,4 +4076,10 @@ yylex() pushback(c); } + } + else if (peek('~')) { + nextc(); + if (!peek('~')) return tFLIP2; + nextc(); + return tFLIP3; } switch (lex_state) {
-- Nobu Nakada