1 2### 3### Copyright 2002-2003 University of Illinois Board of Trustees 4### Copyright 2002-2003 Mark D. Roth 5### All rights reserved. 6### 7### grammar.yp - Parse::Yapp grammar for Config::Objective 8### 9### Mark D. Roth <roth@uiuc.edu> 10### Campus Information Technologies and Educational Services 11### University of Illinois at Urbana-Champaign 12### 13 14 15### 16### Header section 17### 18 19%{ 20use strict; 21 22### 23### constants for conditional evaluation state 24### 25 26### either we already found a true condition, or the parent conditional 27### block is not being evaluated, so: 28### 1. subsequent %else or %elif clauses are NOT evaluated 29### 2. enclosed statements are NOT evaluated 30use constant CS_NO_EVAL => -1; 31 32### have not yet found a true conditional in this block, which means: 33### 1. subsequent %else or %elif clauses are evaluated 34### 2. enclosed statements are NOT evaluated 35use constant CS_FALSE => 0; 36 37### immediately preceding condition was true, so: 38### 1. subsequent %else or %elif clauses are NOT evaluated 39### 2. enclosed statements are evaluated 40use constant CS_TRUE => 1; 41%} 42 43 44%left AND OR 45%right NOT 46 47 48%% 49 50### 51### Rules section 52### 53 54config : #empty 55 | config directive 56 ; 57 58directive 59 : statement 60 | conditional 61 | include 62 ; 63 64include : INCLUDE string 65 { 66 my ($config) = $_[0]->YYData->{'config'}; 67 68 return undef 69 if (@{$config->{'cond_stack'}} 70 && $config->{'cond_stack'}->[-1] != CS_TRUE); 71 72 $_[2] = $config->{'include_dir'} . '/' . $_[2] 73 if ($_[2] !~ m|^/|); 74 75 $config->parse($_[2]); 76 } 77 ; 78 79conditional 80 : cond_if config cond_endif 81 | cond_elif 82 | cond_else 83 ; 84 85expression 86 : expr 87 | NOT expression 88 { 89 return (! $_[2]); 90 } 91 | expression OR expression 92 { 93 return ($_[1] || $_[3]); 94 } 95 | expression AND expression 96 { 97 return ($_[1] && $_[3]); 98 } 99 | PAREN_START expression PAREN_END 100 { 101 return $_[2]; 102 } 103 ; 104 105expr : 106 { 107 my ($config) = $_[0]->YYData->{'config'}; 108 $config->{'in_expr'} = 1; 109 } 110 method_call 111 { 112 my ($config) = $_[0]->YYData->{'config'}; 113 $config->{'in_expr'} = 0; 114 return $_[2]; 115 } 116 ; 117 118cond_if : IF PAREN_START expression PAREN_END 119 { 120 my ($config) = $_[0]->YYData->{'config'}; 121 122 push(@{$config->{'cond_stack'}}, 123 ((@{$config->{'cond_stack'}} 124 && $config->{'cond_stack'}->[-1] != CS_TRUE) 125 ? CS_NO_EVAL 126 : ($_[3] 127 ? CS_TRUE 128 : CS_FALSE))); 129 } 130 ; 131 132cond_endif 133 : ENDIF 134 { 135 my ($config) = $_[0]->YYData->{'config'}; 136 137 die "%endif: not in conditional\n" 138 if (! @{$config->{'cond_stack'}}); 139 140 pop(@{$config->{'cond_stack'}}); 141 } 142 ; 143 144cond_elif 145 : ELIF PAREN_START expression PAREN_END 146 { 147 my ($config) = $_[0]->YYData->{'config'}; 148 149 die "%elif: not in conditional\n" 150 if (! @{$config->{'cond_stack'}}); 151 152 ### all previous conditions were false, so evaluate this one 153 if ($config->{'cond_stack'}->[-1] == CS_FALSE) 154 { 155 $config->{'cond_stack'}->[-1] = ($_[3] 156 ? CS_TRUE 157 : CS_FALSE); 158 } 159 160 ### the last condition was true, so all subsequent %else 161 ### or %elif clauses must be false 162 elsif ($config->{'cond_stack'}->[-1] == CS_TRUE) 163 { 164 $config->{'cond_stack'}->[-1] = CS_NO_EVAL; 165 } 166 167 ### if it's CS_NO_EVAL, leave it alone 168 } 169 ; 170 171cond_else 172 : ELSE 173 { 174 my ($config) = $_[0]->YYData->{'config'}; 175 176 die '%else: not in conditional' 177 if (! @{$config->{'cond_stack'}}); 178 179 ### all previous conditions were false, so set to true 180 if ($config->{'cond_stack'}->[-1] == CS_FALSE) 181 { 182 $config->{'cond_stack'}->[-1] = CS_TRUE; 183 } 184 185 ### the last condition was true, so set to CS_NO_EVAL 186 elsif ($config->{'cond_stack'}->[-1] == CS_TRUE) 187 { 188 $config->{'cond_stack'}->[-1] = CS_NO_EVAL; 189 } 190 191 ### if it's CS_NO_EVAL, leave it alone 192 } 193 ; 194 195string : WORD 196 | QSTRING 197 ; 198 199value : string 200 | list 201 | hash 202 ; 203 204statement 205 : method_call EOS 206 ; 207 208method_name 209 : #empty 210 { 211 my ($config) = $_[0]->YYData->{'config'}; 212 return ($config->{'in_expr'} ? 'equals' : 'default'); 213 } 214 | METHOD_ARROW WORD 215 { 216 return $_[2]; 217 } 218 ; 219 220method_args 221 : #empty 222 { 223 my ($config) = $_[0]->YYData->{'config'}; 224 push(@{$config->{arg_stack}}, []); 225 } 226 | value 227 { 228 my ($config) = $_[0]->YYData->{'config'}; 229 push(@{$config->{arg_stack}}, [ $_[1] ]); 230 } 231 | PAREN_START 232 { 233 my ($config) = $_[0]->YYData->{'config'}; 234 push(@{$config->{'list_stack'}}, []); 235 } 236 list_values PAREN_END 237 { 238 my ($config) = $_[0]->YYData->{'config'}; 239 push(@{$config->{arg_stack}}, pop(@{$config->{'list_stack'}})); 240 } 241 ; 242 243method_call 244 : WORD method_name method_args 245 { 246 my ($config) = $_[0]->YYData->{'config'}; 247 248# print "var='$_[1]' method='$_[2]' value='$_[3]'\n"; 249 250 ### for conditional expressions, don't bother evaluating 251 ### if a previous condition was true 252 return undef 253 if ($config->{'in_expr'} 254 && @{$config->{'cond_stack'}} 255 && $config->{'cond_stack'}->[-1] == CS_NO_EVAL); 256 257 ### for statements, don't evaluate if we're inside a 258 ### false conditional block 259 return undef 260 if (! $config->{'in_expr'} 261 && @{$config->{'cond_stack'}} 262 && $config->{'cond_stack'}->[-1] != CS_TRUE); 263 264 return $config->_call_obj_method($_[1], $_[2], 265 @{pop(@{$config->{arg_stack}})}); 266 } 267 ; 268 269list : LIST_START 270 { 271 my ($config) = $_[0]->YYData->{'config'}; 272 push(@{$config->{'list_stack'}}, []); 273 } 274 list_values LIST_END 275 { 276 my ($config) = $_[0]->YYData->{'config'}; 277 return pop(@{$config->{'list_stack'}}); 278 } 279 ; 280 281list_values 282 : #empty 283 | value 284 { 285 my ($config) = $_[0]->YYData->{'config'}; 286 push(@{$config->{'list_stack'}->[-1]}, $_[1]); 287 } 288 | list_values COMMA value 289 { 290 my ($config) = $_[0]->YYData->{'config'}; 291 push(@{$config->{'list_stack'}->[-1]}, $_[3]); 292 } 293 ; 294 295hash : HASH_START HASH_END 296 { 297 return {}; 298 } 299 | HASH_START 300 { 301 my ($config) = $_[0]->YYData->{'config'}; 302 303 push(@{$config->{'hash_stack'}}, {}); 304 } 305 hash_values HASH_END 306 { 307 my ($config) = $_[0]->YYData->{'config'}; 308 309 return pop(@{$config->{'hash_stack'}}); 310 } 311 ; 312 313hash_values 314 : hash_values COMMA hash_value 315 | hash_value 316 ; 317 318hash_value 319 : string 320 { 321 my ($config) = $_[0]->YYData->{'config'}; 322 323# print "\t'$_[1]' => undef\n"; 324 $config->{'hash_stack'}->[-1]->{$_[1]} = undef; 325 } 326 | string HASH_ARROW value 327 { 328 my ($config) = $_[0]->YYData->{'config'}; 329 330# print "\t'$_[1]' => '$_[3]'\n"; 331 $config->{'hash_stack'}->[-1]->{$_[1]} = $_[3]; 332 } 333 ; 334 335%% 336 337### 338### Footer section 339### 340 341 342