#!/usr/bin/python -O """ # .PDS file parser # # Copyright (C) 2008 Michael Buesch # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ import sys try: from ply import * except ImportError, e: print "Error: " + e.message print "Please install the \"python-ply\" package" sys.exit(1) class PdsEx(Exception): pass class PdsParserBase: t_ignore = " \t\r\032\002\003" def __init__(self, debug): self.debug = debug self.lexer = lex.lex(object=self) self.parser = yacc.yacc(module=self, write_tables=False, debug=debug) def parse(self, text, pds): self.pds = pds self.parser.parse(text, lexer=self.lexer, debug=self.debug) def tokenize(self, text): self.lexer.input(text) tokens = [] while True: t = self.lexer.token() if not t: break tokens.append(t) return tokens # Lexer error handling def t_error(self, t): raise PdsEx("PDS-lexer: Invalid character '%s' at line %s" %\ (t.value[0], t.lineno)) t.skip(1) # Parser error handling def p_error(self, p): self.parserError("Syntax error at \"%s\" (%s)" %\ (p.value, p.lineno)) def parserError(self, text): raise PdsEx("PDS-parser: %s" % text) class SimSeg: "Data structure for a parsed SIMULATION segment" class Signal: def __init__(self, name, inverted=False): self.name = name self.inverted = inverted S_TRACE_ON = 0 S_TRACE_OFF = 1 S_SETF = 2 S_CHECK = 3 S_PRELOAD = 4 S_CLOCKF = 5 def __init__(self): self.items = [] def add(self, type, args): if args: self.items.append([type] + args) else: self.items.append([type]) def getItems(self): "Returns a list of simulation items." return self.items class SimulationParser(PdsParserBase): "Parser for the .PDS file SIMULATION segment" tokens = ( # Keywords "SIM_TRACE_ON", "SIM_TRACE_OFF", "SIM_SETF", "SIM_CHECK", "SIM_PRELOAD", "SIM_CLOCKF", # Other "SIM_NEWLINE", "SIM_COMMENT", "SIM_IDENTIFIER", "SIM_NOT", ) def t_SIM_COMMENT(self, t): r";.*(?=[\r\n])" def t_SIM_NEWLINE(self, t): r"\n" t.lineno += 1 return t def t_SIM_NOT(self, t): r"/" return t def t_SIM_TRACE_ON(self, t): r"TRACE_ON" return t def t_SIM_TRACE_OFF(self, t): r"TRACE_OFF" return t def t_SIM_SETF(self, t): r"SETF" return t def t_SIM_CHECK(self, t): r"CHECK" return t def t_SIM_PRELOAD(self, t): r"PRELOAD" return t def t_SIM_CLOCKF(self, t): r"CLOCKF" return t def t_SIM_IDENTIFIER(self, t): r"[-a-zA-Z0-9\._]+" return t def p_sim_statement(self, p): """sim_statement : sim_traceOn sim_statement | sim_setf sim_statement | sim_check sim_statement | sim_traceOff sim_statement | sim_preload sim_statement | sim_clockf sim_statement | SIM_NEWLINE sim_statement |""" def p_sim_traceOn(self, p): """sim_traceOn : SIM_TRACE_ON sim_signals""" self.pds.sim.add(SimSeg.S_TRACE_ON, p[2]) def p_sim_traceOff(self, p): """sim_traceOff : SIM_TRACE_OFF SIM_NEWLINE""" self.pds.sim.add(SimSeg.S_TRACE_OFF, None) def p_sim_setf(self, p): """sim_setf : SIM_SETF sim_signals""" self.pds.sim.add(SimSeg.S_SETF, p[2]) def p_sim_check(self, p): """sim_check : SIM_CHECK sim_signals""" self.pds.sim.add(SimSeg.S_CHECK, p[2]) def p_sim_preload(self, p): """sim_preload : SIM_PRELOAD sim_signals""" self.pds.sim.add(SimSeg.S_PRELOAD, p[2]) def p_sim_clockf(self, p): """sim_clockf : SIM_CLOCKF sim_signals""" self.pds.sim.add(SimSeg.S_CLOCKF, p[2]) def p_sim_signals(self, p): """sim_signals : sim_signal SIM_NEWLINE | sim_signal sim_signals""" if type(p[2]) == type(""): p[0] = [p[1]] else: p[0] = [p[1]] + p[2] def p_sim_signal(self, p): """sim_signal : SIM_NOT SIM_IDENTIFIER | SIM_IDENTIFIER""" if len(p) == 3: p[0] = SimSeg.Signal(p[2], inverted=True) else: p[0] = SimSeg.Signal(p[1]) class DeclParser(PdsParserBase): "Parser for the .PDS file declarations segment" # define the tokens tokens = ( # Keywords "DECL_TITLE", "DECL_PATTERN", "DECL_REVISION", "DECL_AUTHOR", "DECL_CHIP", "DECL_PIN", "DECL_COMBINATORIAL", "DECL_REGISTERED", "DECL_COMPANY", "DECL_DATE", "DECL_NODE", # Other "DECL_NEWLINE", "DECL_COMMENT", "DECL_IDENTIFIER", ) def t_DECL_COMMENT(self, t): r";.*(?=[\r\n])" def t_DECL_NEWLINE(self, t): r"\n" t.lineno += 1 return t def t_DECL_TITLE(self, t): r"TITLE[-a-zA-Z0-9\. \t/<>@]+(?=[\r\n])" return t def t_DECL_PATTERN(self, t): r"PATTERN[-a-zA-Z0-9\. \t/<>@]+(?=[\r\n])" return t def t_DECL_REVISION(self, t): r"REVISION[-a-zA-Z0-9\. \t/<>@]+(?=[\r\n])" return t def t_DECL_AUTHOR(self, t): r"AUTHOR[-a-zA-Z0-9\. \t/<>@]+(?=[\r\n])" return t def t_DECL_COMPANY(self, t): r"COMPANY[-a-zA-Z0-9\. \t/<>@]+(?=[\r\n])" return t def t_DECL_DATE(self, t): r"DATE[-a-zA-Z0-9\. \t/<>@]+(?=[\r\n])" return t def t_DECL_CHIP(self, t): r"CHIP" return t def t_DECL_PIN(self, t): r"PIN" return t def t_DECL_COMBINATORIAL(self, t): r"COMBINATORIAL" return t def t_DECL_REGISTERED(self, t): r"REGISTERED" return t def t_DECL_NODE(self, t): r"NODE" return t def t_DECL_IDENTIFIER(self, t): r"[-a-zA-Z0-9\._]+" return t def p_decl_statement(self, p): """decl_statement : decl_pinDecl decl_statement | decl_title decl_statement | decl_pattern decl_statement | decl_revision decl_statement | decl_author decl_statement | decl_company decl_statement | decl_date decl_statement | decl_chip decl_statement | decl_node decl_statement | DECL_NEWLINE decl_statement |""" def p_decl_title(self, p): """decl_title : DECL_TITLE DECL_NEWLINE""" v = p[1] self.pds.title = v[len(v.split()[0]):].strip() def p_decl_pattern(self, p): """decl_pattern : DECL_PATTERN DECL_NEWLINE""" v = p[1] self.pds.pattern = v[len(v.split()[0]):].strip() def p_decl_revision(self, p): """decl_revision : DECL_REVISION DECL_NEWLINE""" v = p[1] self.pds.revision = v[len(v.split()[0]):].strip() def p_decl_author(self, p): """decl_author : DECL_AUTHOR DECL_NEWLINE""" v = p[1] self.pds.author = v[len(v.split()[0]):].strip() def p_decl_company(self, p): """decl_company : DECL_COMPANY DECL_NEWLINE""" v = p[1] self.pds.company = v[len(v.split()[0]):].strip() def p_decl_date(self, p): """decl_date : DECL_DATE DECL_NEWLINE""" v = p[1] self.pds.date = v[len(v.split()[0]):].strip() def p_decl_chip(self, p): """decl_chip : DECL_CHIP DECL_IDENTIFIER DECL_IDENTIFIER DECL_NEWLINE""" self.pds.chip = (p[2], p[3]) def p_decl_pinDecl(self, p): """decl_pinDecl : DECL_PIN DECL_IDENTIFIER DECL_IDENTIFIER DECL_COMBINATORIAL DECL_NEWLINE | DECL_PIN DECL_IDENTIFIER DECL_IDENTIFIER DECL_REGISTERED DECL_NEWLINE | DECL_PIN DECL_IDENTIFIER DECL_IDENTIFIER DECL_NEWLINE""" try: pin = int(p[2]) except ValueError, e: self.parserError("Pin number error: %s" % e.message) name = p[3] type = p[4].upper().strip() if type: self.pds.pins.append( (pin, name, type) ) else: self.pds.pins.append( (pin, name) ) def p_decl_node(self, p): """decl_node : DECL_NODE DECL_IDENTIFIER DECL_IDENTIFIER DECL_NEWLINE""" try: nr = p[2] except ValueError, e: self.parserError("Node number error: %s" % e.message) type = p[3] self.pds.node = (nr, type) class Pds: def __init__(self, data, debug=0): self.debug = debug self.title = "" self.pattern = "" self.revision = "" self.author = "" self.company = "" self.date = "" self.chip = ("", "") self.node = (-1, "") self.pins = [] self.sim = None self.__parseData(data) def __parseData(self, text): # First split the data into the file segments lines = text.splitlines() declSeg = [] equationsSeg = [] simulationSeg = [] stateSeg = [] state = "decl" for line in lines: if line.strip().upper().startswith("EQUATIONS"): state = "equ" continue if line.strip().upper().startswith("SIMULATION"): state = "sim" continue if line.strip().upper().startswith("STATE"): state = "state" continue if state == "decl": declSeg.append(line) elif state == "equ": equationsSeg.append(line) elif state == "sim": simulationSeg.append(line) elif state == "state": stateSeg.append(line) else: raise PdsEx("Internal error: __parseData() invalid state") if not declSeg: raise PdsEx("Empty declarations section") declSeg = "\n".join(declSeg) + "\n" if equationsSeg: equationsSeg = "\n".join(equationsSeg) + "\n" if simulationSeg: simulationSeg = "\n".join(simulationSeg) + "\n" if stateSeg: stateSeg = "\n".join(stateSeg) + "\n" # Finally parse all segments self.__parseDeclSeg(declSeg) if equationsSeg: self.__parseEquationsSeg(equationsSeg) if simulationSeg: self.__parseSimulationSeg(simulationSeg) if stateSeg: self.__parseStateSeg(stateSeg) def __parseDeclSeg(self, text): p = DeclParser(self.debug) # for t in p.tokenize(text): print t p.parse(text, self) def __parseEquationsSeg(self, text): pass#TODO def __parseStateSeg(self, text): pass#TODO def __parseSimulationSeg(self, text): self.sim = SimSeg() p = SimulationParser(self.debug) # for t in p.tokenize(text): print t p.parse(text, self) if __name__ == "__main__": try: p = Pds(sys.stdin.read(), debug=1) except PdsEx, e: print "[EXCEPTION]: " + e.message