qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Michael Roth <mdroth@linux.vnet.ibm.com>
To: qemu-devel@nongnu.org
Cc: blauwirbel@gmail.com, peter.maydell@linaro.org,
	aliguori@us.ibm.com, eblake@redhat.com
Subject: [Qemu-devel] [PATCH 19/22] qidl: add C parser (based on QC parser)
Date: Fri, 21 Sep 2012 09:07:42 -0500	[thread overview]
Message-ID: <1348236465-23124-20-git-send-email-mdroth@linux.vnet.ibm.com> (raw)
In-Reply-To: <1348236465-23124-1-git-send-email-mdroth@linux.vnet.ibm.com>

This introduces the QIDL parser to process QIDL annotations in C files.
This code is mostly a straight import from qc.git, with some reworking
to handle the declaration/annotation format and lexer we're using for
QEMU.

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 scripts/qidl_parser.py |  262 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 262 insertions(+)
 create mode 100644 scripts/qidl_parser.py

diff --git a/scripts/qidl_parser.py b/scripts/qidl_parser.py
new file mode 100644
index 0000000..fe155f7
--- /dev/null
+++ b/scripts/qidl_parser.py
@@ -0,0 +1,262 @@
+#
+# QEMU IDL Parser
+#
+# Copyright IBM, Corp. 2012
+#
+# Authors:
+#  Anthony Liguori <aliguori@us.ibm.com>
+#  Michael Roth    <mdroth@linux.vnet.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2.
+# See the COPYING file in the top-level directory.
+
+import sys, json
+from lexer import Input, CLexer
+
+def process_annotation(node, params):
+    annotation_type = params[0]
+    if annotation_type == "derived":
+        node['is_derived'] = True
+    elif annotation_type == 'immutable':
+        node['is_immutable'] = True
+    elif annotation_type == 'elsewhere':
+        node['is_elsewhere'] = True
+    elif annotation_type == 'broken':
+        node['is_broken'] = True
+    elif annotation_type == 'size_is':
+        node['is_array'] = True
+        node['array_size'] = params[1]
+    elif annotation_type == 'optional':
+        node['is_optional'] = True
+    elif annotation_type == 'property':
+        node['is_property'] = True
+        if node.has_key('property_fields'):
+            node['property_fields'].append(params[1:])
+        else:
+            node['property_fields'] = [params[1:]]
+
+    return node
+
+def parse_annotations(l, node):
+    while l.check_token('symbol', 'QIDL'):
+        params = []
+        l.pop()
+
+        l.pop_expected('operator', '(')
+        open_parens = 1
+        param = ""
+        while open_parens:
+            if l.check_token('operator', ','):
+                params.append(param)
+                param = ""
+                l.pop()
+                continue
+
+            if l.check_token('operator', '('):
+                open_parens += 1
+            elif l.check_token('operator', ')'):
+                open_parens -= 1
+
+            if open_parens > 0:
+                param += l.peek()
+
+            l.pop()
+
+        if param != "":
+            params.append(param)
+
+        node = process_annotation(node, params)
+
+    return node
+
+def parse_type(l):
+    node = {}
+
+    typename = ''
+    if l.check_token('const', 'const'):
+        typename += l.pop() + ' '
+
+    if l.check_token('struct', 'struct'):
+        typename += l.pop() + ' '
+
+    if l.check_token('unsigned', 'unsigned'):
+        typename += l.pop() + ' '
+
+    if l.check_token('union', 'union'):
+        typename += l.pop() + ' '
+
+    if l.check_token('enum', 'enum'):
+        typename += l.pop() + ' '
+
+    # we don't currently handle embedded struct declarations, skip them for now
+    if l.check_token('operator', '{'):
+        open_braces = 1
+        while open_braces:
+            l.pop()
+            if l.check_token('operator', '{'):
+                open_braces += 1
+            elif l.check_token('operator', '}'):
+                open_braces -= 1
+        l.pop()
+        typename += "<anon>"
+        node['is_nested_decl'] = True
+    else:
+        if l.check_token('operator', '*'):
+            l.pop()
+            node['is_pointer'] = True
+        else:
+            typename += l.pop_expected('symbol')
+
+    node['type'] = typename
+
+    node = parse_annotations(l, node)
+
+    if l.check_token('operator', '*'):
+        l.pop()
+        node['is_pointer'] = True
+
+    return node
+
+def parse_var_decl(l, repeating_type=None):
+    if repeating_type == None:
+        node = parse_type(l)
+    else:
+        node = { 'type': repeating_type }
+
+    if l.check_token('operator', '('):
+        node['is_function'] = True
+        l.pop()
+        l.pop_expected('operator', '*')
+        variable = l.pop_expected('symbol')
+        l.pop_expected('operator', ')')
+
+        # skip the param list since we don't use it currently
+        l.pop_expected('operator', '(')
+        open_parens = 1
+        while open_parens:
+            if l.check_token('operator', '('):
+                open_parens += 1
+            elif l.check_token('operator', ')'):
+                open_parens -= 1
+            l.pop()
+    else:
+        variable = l.pop_expected('symbol')
+    node['variable'] = variable
+
+    if l.check_token('operator', '['):
+        l.pop()
+        expression = ""
+        while not l.check_token('operator', ']'):
+            expression += l.pop()
+        l.pop_expected('operator', ']')
+
+        if not node.has_key('is_array'):
+            node['is_array'] = True
+            node['array_size'] = expression
+        else:
+            node['array_capacity'] = expression
+
+    node = parse_annotations(l, node)
+
+    return node
+
+def parse_struct(l):
+    l.pop_expected('struct', 'struct')
+
+    name = None
+    if l.check_token('symbol'):
+        name = l.pop()
+
+    l.pop_expected('operator', '{')
+
+    nodes = []
+
+    while not l.check_token('operator', '}'):
+        node = parse_var_decl(l)
+        nodes.append(node)
+        while l.check_token('operator', ','):
+            l.pop()
+            node = parse_var_decl(l, node['type'])
+            nodes.append(node)
+
+        l.pop_expected('operator', ';')
+
+    l.pop()
+
+    return { 'struct': name, 'fields': nodes }
+
+def parse_typedef(l):
+    l.pop_expected('typedef', 'typedef')
+
+    node = parse_struct(l)
+    typename = l.pop_expected('symbol')
+
+    return { 'typedef': typename, 'type': node }
+
+def parse_declaration_params(l):
+    declaration_info = {}
+    params = []
+    arg_string = ""
+    parens = 0
+    l.pop_expected('symbol', 'QIDL_START')
+    while not l.eof():
+        if l.check_token('operator', '('):
+            parens += 1
+        elif l.check_token('operator', ')'):
+            parens -= 1
+            if parens == 0:
+                break
+        elif parens > 0:
+            if not l.check_token('operator', ','):
+                params.append(l.peek())
+        l.pop()
+    l.pop_expected('operator', ')')
+    if parens != 0:
+        raise Exception("unmatched parenthesis in QIDL macro")
+
+    declaration_info['id'] = params[0]
+    declaration_info['do_state'] = True
+    declaration_info['do_properties'] = True
+    if "skip_state" in params:
+        declaration_info['do_state'] = False
+    if "skip_properties" in params:
+        declaration_info['do_properties'] = False
+
+    return declaration_info
+
+def parse_declaration(l):
+    declaration_info = parse_declaration_params(l)
+
+    if l.check_token('typedef'):
+        node = parse_typedef(l)
+    elif l.check_token('struct'):
+        node = parse_struct(l)
+    else:
+        raise Exception("unsupported QIDL declaration")
+
+    l.pop_expected('operator', ';')
+    node['id'] = declaration_info['id']
+    node['do_state'] = declaration_info['do_state']
+    node['do_properties'] = declaration_info['do_properties']
+
+    return node
+
+def parse_file(f):
+    nodes = []
+    filtered_tokens = ['whitespace', 'comment', 'directive']
+    l = CLexer(Input(f), filtered_tokens)
+    while not l.eof():
+        line = l.peek_line()
+        if line.startswith("QIDL_START("):
+            node = parse_declaration(l)
+            nodes.append(node)
+        else:
+            l.pop_line()
+    return nodes
+
+def main():
+    nodes = parse_file(sys.stdin)
+    print json.dumps(nodes, sort_keys=True, indent=2)
+
+if __name__ == '__main__':
+    main()
-- 
1.7.9.5

  parent reply	other threads:[~2012-09-21 14:08 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-09-21 14:07 [Qemu-devel] [PATCH v2] Add infrastructure for QIDL-based device serialization Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 01/22] qapi: qapi-visit.py -> qapi_visit.py so we can import Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 02/22] qapi: qapi-types.py -> qapi_types.py Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 03/22] qapi: qapi-commands.py -> qapi_commands.py Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 04/22] qapi: qapi_visit.py, make code useable as module Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 05/22] qapi: qapi_visit.py, support arrays and complex qapi definitions Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 06/22] qapi: qapi_visit.py, support generating static functions Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 07/22] qapi: qapi_visit.py, support for visiting non-pointer/embedded structs Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 08/22] qapi: add visitor interfaces for C arrays Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 09/22] qapi: QmpOutputVisitor, implement array handling Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 10/22] qapi: QmpInputVisitor, " Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 11/22] qapi: qapi.py, make json parser more robust Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 12/22] qapi: add open-coded visitor for struct tm types Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 13/22] qom-fuse: force single-threaded mode to avoid QMP races Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 14/22] qom-fuse: workaround for truncated properties > 4096 Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 15/22] module additions for schema registration Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 16/22] qdev: move Property-related declarations to qdev-properties.h Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 17/22] qidl: add documentation Michael Roth
2012-09-21 23:16   ` Eric Blake
2012-09-21 14:07 ` [Qemu-devel] [PATCH 18/22] qidl: add lexer library (based on QC parser) Michael Roth
2012-09-21 23:18   ` Eric Blake
2012-09-21 23:52     ` Michael Roth
2012-09-25 21:09       ` Anthony Liguori
2012-09-21 14:07 ` Michael Roth [this message]
2012-09-21 23:19   ` [Qemu-devel] [PATCH 19/22] qidl: add C parser " Eric Blake
2012-09-21 14:07 ` [Qemu-devel] [PATCH 20/22] qidl: add QAPI-based code generator Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 21/22] qidl: qidl.h, definitions for qidl annotations Michael Roth
2012-09-21 14:07 ` [Qemu-devel] [PATCH 22/22] qidl: unit tests and build infrastructure Michael Roth
2012-09-21 15:57 ` [Qemu-devel] [PATCH v2] Add infrastructure for QIDL-based device serialization Paolo Bonzini
2012-09-21 16:24   ` Michael Roth
2012-09-22 14:33     ` Blue Swirl
2012-09-24 18:14       ` Michael Roth
2012-09-25  6:37         ` Paolo Bonzini
2012-09-25 15:45           ` Michael Roth
2012-09-25 21:12             ` Anthony Liguori
2012-09-26  9:57               ` Paolo Bonzini
2012-09-26 10:20               ` Kevin Wolf
2012-09-26 10:33                 ` Paolo Bonzini
2012-09-26 15:12                   ` Michael Roth

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1348236465-23124-20-git-send-email-mdroth@linux.vnet.ibm.com \
    --to=mdroth@linux.vnet.ibm.com \
    --cc=aliguori@us.ibm.com \
    --cc=blauwirbel@gmail.com \
    --cc=eblake@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).