Source code for taurus.core.util.property_parser

#!/usr/bin/env python

#############################################################################
##
# This file is part of Taurus
##
# http://taurus-scada.org
##
# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
##
# Taurus is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
##
# Taurus 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 Lesser General Public License for more details.
##
# You should have received a copy of the GNU Lesser General Public License
# along with Taurus.  If not, see <http://www.gnu.org/licenses/>.
##
#############################################################################

"""This is an experimental property parser"""

from __future__ import print_function
from builtins import str

import os
import ply.lex as lex
import ply.yacc as yacc
from .containers import CaselessDict
from .log import Logger

reserved = CaselessDict({
    'true': 'true',
    'false': 'false',
    'yes': 'yes',
    'no': 'no'
})

tokens = ['EQUALS',
          'KEY',
          'STRING',
          'NUMBER',
          'COMMA',
          'LLST', 'RLST',
          #'LBRACKET', 'RBRACKET',
          ] + list(reserved.values())

t_EQUALS = r'\='
t_LLST = r'\['
t_RLST = r'\]'
t_COMMA = r'\,'
#t_LBRACKET = r'\{'
#t_RBRACKET = r'\}'


[docs]def t_NUMBER(t): r'[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?' try: if t.value.count('.') == 0: try: t.value = int(t.value) except: t.value = float(t.value) else: t.value = float(t.value) except: print("[%d]: Number %s is not valid!" % (t.lineno, t.value)) t.value = 0 return t
# The following backslash sequences have their usual special meaning: \", # \\, \n, and \t.
[docs]def t_STRING(t): r'\"([^\\"]|(\\.))*\"' escaped = 0 str = t.value[1:-1] new_str = "" for i in range(0, len(str)): c = str[i] if escaped: if c == "n": c = "\n" elif c == "t": c = "\t" new_str += c escaped = 0 else: if c == "\\": escaped = 1 else: new_str += c t.value = new_str return t
[docs]def t_KEY(t): r'[a-zA-Z0-9/_\.\/]+' t.type = reserved.get(t.value, 'KEY') # Check for reserved words return t
# Ignored characters t_ignore = ' \t' t_ignore_COMMENT = r'\#.*'
[docs]def t_newline(t): r'\n+' t.lexer.lineno += t.value.count("\n")
[docs]def t_error(t): print("[%d]: Illegal character '%s'" % (t.lexer.lineno, t.value[0])) t.lexer.skip(1)
[docs]def p_error(p): print("[%d]: Syntax error in input [%s]" % (p.lineno, (str(p))))
#------------------------------------------------------------------------- # Yacc Starting symbol #-------------------------------------------------------------------------
[docs]def p_property_file(p): '''property_file : statement_list |''' if len(p) == 1: p[0] = {} else: p[0] = p[1]
[docs]def p_statement_list(p): '''statement_list : statement_list statement''' p[1].update(p[2]) p[0] = p[1]
[docs]def p_statement(p): '''statement_list : statement''' p[0] = p[1]
[docs]def p_statement_assign(p): '''statement : KEY EQUALS value''' p[0] = {p[1]: p[3]}
[docs]def p_value(p): '''value : atomic | list''' p[0] = p[1]
[docs]def p_value_atomic(p): '''atomic : KEY | STRING | NUMBER | boolean''' p[0] = p[1]
[docs]def p_value_boolean(p): '''boolean : true | false | yes | no''' v = p[1].lower() p[0] = v in ('true', 'yes')
[docs]def p_value_list(p): '''list : LLST value_list RLST''' p[0] = p[2]
[docs]def p_value_list_elems1(p): '''value_list : value_list COMMA value''' p[0] = p[1] + [p[3]]
[docs]def p_value_list_elems2(p): '''value_list : value''' p[0] = [p[1]]
[docs]class PropertyParser(Logger): def __init__(self, parent=None): name = self.__class__.__name__ self.call__init__(Logger, name, parent) self._last_filename = None
[docs] def parse_file(self, f, logger=None, debug=0, optimize=1): self._last_filename = os.path.abspath(f.name) kw = { 'debuglog': logger or self, 'errorlog': logger or self, 'debug': debug, 'optimize': optimize, } kw_lex = kw.copy() kw_lex.update({'lextab': 'property_lextab'}) kw_yacc = kw.copy() kw_yacc.update({'tabmodule': 'property_yacctab'}) lexer = lex.lex(**kw_lex) parser = yacc.yacc(**kw_yacc) if debug: debug = self return parser.parse(f.read(), debug=debug, lexer=lexer)
[docs] def parse(self, filename, logger=None, debug=0, optimize=1): filename = os.path.realpath(filename) f, res = None, None try: f = open(filename) res = self.parse_file( f, logger=logger, debug=debug, optimize=optimize) f.close() except IOError as e: if f: f.close() raise return res
[docs] def getLastFilename(self): return self._last_filename
if __name__ == '__main__': import sys pp = PropertyParser() res = pp.parse(sys.argv[1]) print(res)