Changes between Version 5 and Version 6 of PGEBestPractices
- Timestamp:
- 06/30/09 01:28:24 (13 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
PGEBestPractices
v5 v6 2 2 3 3 == Parsing Techniques == 4 5 The techniques listed here are things you might want to try. They're definitely not things you must do, only things that have helped in the past. 4 6 5 7 === ''Everything'' goes on a stack === … … 34 36 Remember when building PAST trees that the parser is "experimenting" with your rule. Maybe this is an expression, but maybe it's an anonymous declaration. 35 37 36 As a result, you may build a very complex parse tree only to have the parser decide it's wrong, and discard it. Consider having some "sequence points" in your grammar where you can be sure that the parser has correctly identifie rwhatever it is you are building.38 As a result, you may build a very complex parse tree only to have the parser decide it's wrong, and discard it. Consider having some "sequence points" in your grammar where you can be sure that the parser has correctly identified whatever it is you are building. 37 39 38 40 Consider a variable declaration. If you store the variable declaration in a lexical block, and the parser decides that those curly braces don't ''really'' indicate a block, there's no harm. The connection from declaration to block was encapsulated in the block itself, so discarding the block's PAST tree discards the variable declaration. 39 41 40 But if you interpret a variable declaration as some kind of global, and jam a symbol into a namespace, then what will you do if the parse fails? The parser might find a valid alternative, but you've injected a bogus symbol into the symtable someplace.42 But if you interpret a variable declaration as some kind of global, and jam a symbol into a namespace, then what will you do if the parse fails? The parser might find a valid alternative, but you've already injected a bogus symbol into the symtable someplace. 41 43 42 For a dynamic language, the best way to deal with this m ay be to ignore it -- let autovivification solve the problem. Alternatively, you may want to create a "transaction" block representing changes to the namespace, and merge that block when the parser returns to some higher level (the sequence points mentioned before: a completed function decl, for example).44 For a dynamic language, the best way to deal with this might be to ignore it -- let autovivification solve the problem. Or, you may want to create a "transaction" block representing changes to the namespace, and merge that block when the parser returns to some higher level (the sequence points mentioned before: a completed function decl, for example). 43 45 44 46 === Use 'state' variables to avoid special cases === … … 46 48 For handling non-local conditions, like "first time this occurs" or "first one in file", use a state variable instead of trying to build a complex pattern. This can be used to start parsing with a "default" configuration that skips certain productions. 47 49 {{{ 48 rule TOP {49 {{ $P0 = box 150 set_global '$Top_of_file', $P051 }}50 rule TOP { 51 {{ $P0 = box 1 52 set_global '$Top_of_file', $P0 53 }} 52 54 53 # ... rest of rule 54 } 55 <section>* 56 {*} 57 } 55 58 56 rule section {57 [ <section_header>59 rule section { 60 [ <section_header> 58 61 59 || # Note: Section Header is OPTIONAL at top of file60 <?{{ $P0 = get_global '$Top_of_file'62 || # Note: Section Header is OPTIONAL at top of file 63 <?{{ $P0 = get_global '$Top_of_file' 61 64 .return($P0) 62 }}>63 ]64 # Not at TOF anymore.65 {{ $P0 = box 066 set_global '$Top_of_file', $P067 }}65 }}> 66 ] 67 # Not at TOF anymore. 68 {{ $P0 = box 0 69 set_global '$Top_of_file', $P0 70 }} 68 71 69 # ... rest of rule70 }72 # ... rest of rule 73 } 71 74 }}} 72 75 … … 78 81 {{{ 79 82 rule variable_decl { 80 <storage_class> <type> <init_declarator> 83 <storage_class> 84 <type> 85 <init_declarator> 81 86 } 82 87 83 88 rule parameter_decl { 84 <type> <init_declarator> 89 <type> 90 <init_declarator> 85 91 } 86 92 }}} … … 93 99 } 94 100 }}} 95 The mode is a special token that just executes some inline PIR code: 101 The first line, above, looks like `[ A B ]?` where B happens to be an optional rule. That structure essentially means that if A is present, B is required also. It's a useful pattern for guard conditions. 102 103 The mode rule is a special token that just executes some inline PIR code: 96 104 {{{ 97 105 token DECL_MODE_PARAM { … … 119 127 }}} 120 128 Note that the parser may try several alternatives, so don't try to insert error messages too early in the rule. In the example above, the '{' is the key indicator of a compound statement. It makes no sense to try to report a "Compound statement missing '{'" error, since the failure of the rule may tell the parser to try some other, valid subrule. But once the block is opened, it will obviously have to be closed. 129 130 Note also that there is no `error()` method by default. You can start out using `panic()`, but you'll want to attach a less dramatic mechanism to your parser eventually. 121 131 122 132 == Performance == … … 146 156 147 157 If several rules can be uniquely distinguished by a simple prefix, hoist the prefix into a parent rule. 148 149 158 {{{ 150 159 rule built_in_function { … … 165 174 } 166 175 }}} 167 176 The more completely you hoist, the more code you eliminate. Ideally you'll save the keyword for later use, maybe restructuring the rule to build the function call in pieces. (Put it on a stack!) 168 177 169 178 == Debugging ==