1#!/usr/bin/python 2# Copyright (c) 2012 The Native Client Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6""" 7A simple recursive-descent parser for the table file format. 8 9The grammar implemented here is roughly (taking some liberties with whitespace 10and comment parsing): 11 12table_file ::= ( BLANK_LINE | table_def ) end_of_file ; 13table_def ::= "--" IDENT CITATION NL 14 table_header 15 ( table_row )+ ; 16table_header ::= ( IDENT "(" BITRANGE ")" )+ ; 17table_row ::= ( PATTERN )+ ACTION ; 18 19IDENT = /[a-z0-9_]+/ 20CITATION = "(" /[^)]+/ ")" 21BITRANGE = /[0-9]+/ (":" /[0-9]+/)? 22PATTERN = /[10x_]+/ 23ACTION = ( "=" IDENT | "->" IDENT ) ( "(" IDENT ")" )? 24NL = a newline 25BLANK_LINE = what you might expect it to be 26""" 27 28import re 29import dgen_core 30 31# These globals track the parser state. 32_in = None 33_line_no = None 34_tables = None 35_line = None 36_last_row = None 37 38 39def parse_tables(input): 40 """Entry point for the parser. Input should be a file or file-like.""" 41 global _in, _line_no, _tables 42 _in = input 43 _line_no = 0 44 _tables = [] 45 next_line() 46 47 while not end_of_file(): 48 blank_line() or table_def() or unexpected() 49 50 return _tables 51 52 53def blank_line(): 54 if _line: 55 return False 56 57 next_line() 58 return True 59 60 61def table_def(): 62 global _last_row 63 64 m = re.match(r'^-- ([^ ]+) \(([^)]+)\)', _line) 65 if not m: return False 66 67 table = dgen_core.Table(m.group(1), m.group(2)) 68 next_line() 69 while blank_line(): pass 70 71 table_header(table) 72 _last_row = None 73 while not end_of_file() and not blank_line(): 74 table_row(table) 75 76 _tables.append(table) 77 return True 78 79 80def table_header(table): 81 for col in _line.split(): 82 m = re.match(r'^([a-z0-9_]+)\(([0-9]+)(:([0-9]+))?\)$', col, re.I) 83 if not m: raise Exception('Invalid column header: %s' % col) 84 85 hi_bit = int(m.group(2)) 86 if m.group(4): 87 lo_bit = int(m.group(4)) 88 else: 89 lo_bit = hi_bit 90 table.add_column(m.group(1), hi_bit, lo_bit) 91 next_line() 92 93 94def table_row(table): 95 global _last_row 96 97 row = _line.split() 98 for i in range(0, len(row)): 99 if row[i] == '"': row[i] = _last_row[i] 100 _last_row = row 101 102 action = row[-1] 103 patterns = row[:-1] 104 table.add_row(patterns, action) 105 next_line() 106 107 108def end_of_file(): 109 return _line is None 110 111 112def next_line(): 113 global _line_no, _line 114 115 _line_no += 1 116 _line = _in.readline() 117 if _line: 118 _line = re.sub(r'#.*', '', _line).strip() 119 else: 120 _line = None 121 122 123def unexpected(): 124 raise Exception('Line %d: Unexpected line in input: %s' % (_line_no, _line)) 125