使用BEGIN和END解析具有无限数量的嵌套数组的数据文件

Looking for an answer either in pseudo or workable in PHP if you're feeling generous.

Currently I have a file with the following syntax:

ITEM 1
Pet Dog
Origin Earth
BEGIN Square
   ITEM 2
   BEGIN "0 0" Type "Earth over" Temp 0.1 END
   BEGIN "0 1" Type "Earth over" Temp 0.1 END
   BEGIN "0 2" Earth 0.1827 END
END
BEGIN "0100"
   ITEM 2
   Origin Earth
   BEGIN Alpha
      ID 1
      Name Alpha
   END
   BEGIN "Need"
      BEGIN "00" id.a END
      BEGIN "01" id.b END
   END
END

I wish to be able to take this and parse this into a usable array similar to this:

array(
   "ITEM" => "1",
   "Pet" => "Dog",
   "Origin" => "Earth",
   "Square" => array(
      "ITEM" => "2",
      "0 0" => array(
         "Type" => "Earth over",
         "Temp" => "0.1"
      ),
      "0 1" => array(
         "Type" => "Earth over",
         "Temp" => "0.1"
      ),
      "0 2" => array(
         "Earth" => "0.1827"
      ),
   ),
   "0100" => array(
      "ITEM" => "2",
      "Origin" => "Earth",
      "Alpha" => array(
         "ID" => "1",
         "Name" => "Alpha"
      ),
      "Need" => array(
         "00" => "id.a",
         "01" => "id.b"
      )
   )
)

Note that I'm not worried about value types - strings are perfectly fine for what I'm doing.

This is a function that parses that text. It may need adjustments and additions if the format is more complex than is exposed in the question. It also needs some error handling when the input data does not match the expected format.

/**
 * Parse the provided lines of text into an array.
 * Warning: it modifies the input parameter. At the end of the execution, $lines will be empty.
 */
function parseData(array &$lines)
{
    $result = array();                                 // this is where the current block is stored

    // Process one line at a time...
    do {
        $l = trim(array_shift($lines));                // extract the first line into $l (and remove it from $lines)
        $p = str_getcsv($l, ' ', '"');                 // split $l into words (take care of strings eclosed in quotes)

        $key = array_shift($p);                        // get the first word from the line
        switch ($key)
        {
        default:                                       // simple "key value" lines
            $result[$key] = implode(' ', $p);          // combine the remaining words from $p into a single string
            break;

        case 'BEGIN':                                  // start a new block
            $key = array_shift($p);                    // the real key in the array follows the 'BEGIN' keyword
            if (end($p) == 'END') {                    // check if the entire block is on a single line
                array_pop($p);                         // remove 'END' from the end of the array
                if (count($p) == 1) {                  // only one word remaining in $p:
                     $result[$key] = array_shift($p);  //              it is the value
                } else {                               // more than one word in $p: this is a list of properties
                     $aa = array();                    // put the values of this one-line block here
                     while (count($p) > 1) {
                         $k = array_shift($p);         // they come in pairs: key followed by value
                         $v = array_shift($p);
                         $aa[$k] = $v;
                     }
                     $result[$key] = $aa;              // the entire line was parsed; store it
                }
            } else {                                   // the last word on the line is not 'END'
                $result[$key] = parseData($lines);     // recursively call this function to parse the inner block and store its result
            }                                          // it will return after it consumes the line that starts with 'END'
            break;

        case 'END':                                    // here ends the block
            return $result;                            // return the collected values
        }

    } while (count($lines));                           // ... until there are no more lines to process

    return $result;                                    // no more lines to process; return the collected data
}

How to use it:

$text  = file_get_contents('1.txt');
$lines = explode("
", trim($text));

$data = parseData($lines);
print_r($data);