Re: [PHP4BETA] zend-parser.y shift/reduce conflicts and suggestions

From: Date: Wed, 18 Aug 1999 00:04:10 +0000
Subject: Re: [PHP4BETA] zend-parser.y shift/reduce conflicts and suggestions
References: 1  Groups: php.version4 
Request: Send a blank email to php-version4+get-3532@lists.php.net to get a copy of this message
It was a suggestion, because my solution effectively removes 2 shift/reduce conflicts, and removes about a hundred of parser states. Removing them cleanly is always good prior to make significant additions to the syntax. Also I have some quirks in the syntax accepted by the language by looking at nullable tokens. For example the grammar accepts several consecutive commas with no expressions between them. This gives some strange statements like: echo,,,,,,,,; and for(,,,,,,,,,;,,,,,,,,,;,,,,,,,,,); The quirks on 'echo_expr' are harmless, because no expression means no code generated. However the quirks on the 'for_expr' generates unuseful code that produces a boolean true expression which gets evaluated at run-time. Also I have noticed that the code generation for the 'switch/case/default' statement was not efficient as it could, because it generates too many ZEND_JMP and ZEND_JMPZ opcodes. Don't you think that the opcodes associated to the switch labels could be stored in another structure, so that the labelled statements that follow the switch() could be generated as a whole single block with no added jumps ? For that you would only need to generate an initial opcode for the switch, with the condition expression in one branch, and the second branch reserved for the jump table, that could be either stored in the main opcodes-array after the code for the labelled statements. A simple generation scheme could then be: ZEND source address: opcodes (trigrams) ------------------ --------------------------------------- switch(expr) { <result=expr> <ZEND_SWITCH,result,jumptable> case 1: case 2: statements; addr_1: <opcodes for statements> break; <ZEND_JMP,end_switch,nil> case 3: statements; addr_2: <opcodes for statements> /*falls thru*/ case 4: statements: addr_3: <opcodes for statements> default: statements: addr_4: <opcodes for statements> } <ZEND_JMP,end_switch,nil> jumptable: <ZEND_CASE,addr_1,1> <ZEND_CASE,addr_1,2> <ZEND_CASE,addr_2,3> <ZEND_CASE,addr_3,4> <ZEND_JMP,addr_4,nil> end_switch: Note that this introduces a ZEND_SWITCH opcode, which is a special form of branch like ZEND_JUMP. One of its branchs links to the expression, the other branch links to the jump table. When executing this opcode, it simply scans the jump table to find a match in the ZEND_CASE opcodes. If there is no ZEND_CASE opcode which matches the expression, it simply jumps after the list of ZEND_CASE opcodes. At that place there may be a classic ZEND_JMP opcode that can bring it to the optional default case. Note that the new ZEND_CASE opcode is then a trigram, unlike the ZEND_JMPZ opcode used for now. A ZEND_CASE opcode cannot be executed alone by itself: it's an invalid opcode anywhere in the zend_execute() loop, unless it is scanned by a ZEND_SWITCH opcode which actually only reads it. A ZEND_CASE opcode can also store source filename and linenumber for debugging and exception handling like all other opcodes... ZEND_SWITCH scans opcodes until it finds either a case match or another opcode. If a match is found, it jumps to the address indicated by the opcode operand. If no match is found (ZEND_SWITCH does not find a matching ZEND_CASE opcode), then ZEND_SWITCH simply branches at the next opcode that follows the last ZEND_CASE. Note that the last opcode of the labelled statement block must be terminated by an unconditional jump to the end of the switch, this avoids executing the invalid ZEND_CASE opcodes and the possible ZEND_JMP for the default case. For the parse-time code generation, all that is needed is to allocate a dynamic array to store ZEND_CASE opcodes, while other statements in the labelled block can be generated on the fly. Such an array will reasonably be small because it only stores constants and opcode addresses within the generated opcodes for the labelled block. This array cannot be global, because there can be sevral embedded switch statements. However, its address can be kept at the top of the zend parser stack already used to store the state of embedded loops and switchs. ----- Original Message ----- From: Andi Gutmans <andi@zend.com> To: Philippe Verdy <verdy_p@wanadoo.fr>; <php4beta@lists.php.net> Sent: Tuesday, August 17, 1999 10:56 PM Subject: Re: [PHP4BETA] zend-parser.y shift/reduce conflicts and suggestions > I don't see a problem with the current parsing file. > The if/elseif/else shift/reduce conflict is resolved correctly. It is > shifted. This is the way the dangling else problem should be handled. > > Andi > --- > Andi Gutmans <andi@zend.com> > http://www.zend.com/ >

« previous php.version4 (#3532) next »