| # ************************************************************* |
| # |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| # |
| # ************************************************************* |
| |
| |
| import sys |
| from globals import * |
| import srclexer |
| |
| class MacroParser(object): |
| |
| def __init__ (self, buf): |
| self.buffer = buf |
| self.macro = None |
| self.debug = False |
| |
| def parse (self): |
| """ |
| A macro with arguments must have its open paren immediately following |
| its name without any whitespace. |
| """ |
| if self.debug: |
| print("-"*68) |
| print("parsing '%s'"%self.buffer) |
| |
| i = 0 |
| bufSize = len(self.buffer) |
| name, buf = '', '' |
| while i < bufSize: |
| c = self.buffer[i] |
| if c in [' ', "\t"] and len(name) == 0: |
| # This is a simple macro with no arguments. |
| name = buf |
| vars = [] |
| content = self.buffer[i:] |
| self.setMacro(name, vars, content) |
| return |
| elif c == '(' and len(name) == 0: |
| # This one has arguments. |
| name = buf |
| buf = self.buffer[i:] |
| vars, content = self.parseArgs(buf) |
| self.setMacro(name, vars, content) |
| return |
| else: |
| buf += c |
| i += 1 |
| |
| def parseArgs (self, buffer): |
| """Parse arguments. |
| |
| The buffer is expected to be formatted like '(a, b, c)' where the first |
| character is the open paren. |
| """ |
| scope = 0 |
| buf = '' |
| vars = [] |
| content = '' |
| bufSize = len(buffer) |
| i = 0 |
| while i < bufSize: |
| c = buffer[i] |
| if c == '(': |
| scope += 1 |
| elif c == ')': |
| scope -= 1 |
| if len(buf) > 0: |
| vars.append(buf) |
| if scope == 0: |
| break |
| elif c == ',': |
| if len(buf) == 0: |
| raise globals.ParseError ('') |
| vars.append(buf) |
| buf = '' |
| elif c in " \t" and scope > 0: |
| pass |
| else: |
| buf += c |
| |
| i += 1 |
| |
| if scope > 0: |
| raise globals.ParseError ('') |
| |
| return vars, buffer[i+1:] |
| |
| |
| def setMacro (self, name, vars, content): |
| if self.debug: |
| print("-"*68) |
| print("name: %s"%name) |
| for var in vars: |
| print("var: %s"%var) |
| if len(vars) == 0: |
| print("no vars") |
| print("content: '%s'"%content) |
| |
| if len(content) > 0: |
| self.macro = Macro(name) |
| for i in range(0, len(vars)): |
| self.macro.vars[vars[i]] = i |
| |
| # tokinize it using lexer. |
| mclexer = srclexer.SrcLexer(content) |
| mclexer.expandHeaders = False |
| mclexer.inMacroDefine = True |
| mclexer.tokenize() |
| self.macro.tokens = mclexer.getTokens() |
| if self.debug: |
| print(self.macro.tokens) |
| |
| if not self.isValidMacro(self.macro): |
| self.macro = None |
| |
| if self.debug: |
| if self.macro != None: |
| print("macro registered!") |
| else: |
| print("macro not registered") |
| |
| def isValidMacro (self, macro): |
| |
| n = len(macro.tokens) |
| if n == 0: |
| return False |
| elif len(macro.name) > 4 and macro.name[1:4] == 'ID_': |
| # We don't want to expand macros like HID_, SID_, WID_, etc. |
| return False |
| return True |
| |
| |
| def getMacro (self): |
| return self.macro |