Add a ProtocolInfo class that is specialized (through inheritance) for each protocol. This class currently has the protocol's name and any protocol-specific options (partial_func_reads is the only one so far). Note that the SLICC language has been updated so that you can specify the options in the `protocol` statement in the `.slicc` file. Signed-off-by: Jason Lowe-Power <jason@lowepower.com>
862 lines
25 KiB
Python
862 lines
25 KiB
Python
# Copyright (c) 2020,2021 ARM Limited
|
|
# All rights reserved.
|
|
#
|
|
# The license below extends only to copyright in the software and shall
|
|
# not be construed as granting a license to any other intellectual
|
|
# property including but not limited to intellectual property relating
|
|
# to a hardware implementation of the functionality of the software
|
|
# licensed hereunder. You may use the software subject to the license
|
|
# terms below provided that you ensure that this notice is replicated
|
|
# unmodified and in its entirety in all distributions of the software,
|
|
# modified or unmodified, in source code or in binary form.
|
|
#
|
|
# Copyright (c) 2009 The Hewlett-Packard Development Company
|
|
# Copyright (c) 2017 Google Inc.
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions are
|
|
# met: redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer;
|
|
# redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution;
|
|
# neither the name of the copyright holders nor the names of its
|
|
# contributors may be used to endorse or promote products derived from
|
|
# this software without specific prior written permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
import os.path
|
|
import re
|
|
import sys
|
|
|
|
from code_formatter import code_formatter
|
|
from grammar import (
|
|
Grammar,
|
|
ParseError,
|
|
)
|
|
|
|
import slicc.ast as ast
|
|
import slicc.util as util
|
|
from slicc.symbols import SymbolTable
|
|
|
|
|
|
class SLICC(Grammar):
|
|
def __init__(
|
|
self,
|
|
protocol,
|
|
includes,
|
|
base_dir,
|
|
verbose=False,
|
|
traceback=False,
|
|
**kwargs,
|
|
):
|
|
"""Entrypoint for SLICC parsing
|
|
protocol: The protocol `.slicc` file to parse
|
|
includes: list of `.slicc` files that are shared between all protocols
|
|
"""
|
|
self.protocol = None
|
|
self.traceback = traceback
|
|
self.verbose = verbose
|
|
self.symtab = SymbolTable(self)
|
|
self.base_dir = base_dir
|
|
|
|
# Update slicc_interface/ProtocolInfo.cc/hh if updating this.
|
|
self.options = {
|
|
"partial_func_reads": False,
|
|
"use_secondary_store_conditional": False,
|
|
}
|
|
|
|
if not includes:
|
|
# raise error
|
|
pass
|
|
|
|
try:
|
|
self.decl_list = self.parse_file(includes[0], **kwargs)
|
|
for include in includes[1:]:
|
|
self.decl_list += self.parse_file(include, **kwargs)
|
|
# set all of the types parsed so far as shared
|
|
self.decl_list.setShared()
|
|
|
|
self.decl_list += self.parse_file(protocol, **kwargs)
|
|
except ParseError as e:
|
|
if not self.traceback:
|
|
sys.exit(str(e))
|
|
raise
|
|
|
|
def currentLocation(self):
|
|
return util.Location(
|
|
self.current_source, self.current_line, no_warning=not self.verbose
|
|
)
|
|
|
|
def codeFormatter(self, *args, **kwargs):
|
|
code = code_formatter(*args, **kwargs)
|
|
code["protocol"] = self.protocol
|
|
return code
|
|
|
|
def process(self):
|
|
self.decl_list.generate()
|
|
|
|
def writeCodeFiles(self, code_path, includes):
|
|
self.symtab.writeCodeFiles(code_path, includes)
|
|
|
|
def writeHTMLFiles(self, html_path):
|
|
self.symtab.writeHTMLFiles(html_path)
|
|
|
|
def files(self):
|
|
f = {os.path.join(self.protocol, "Types.hh")}
|
|
|
|
f |= self.decl_list.files()
|
|
|
|
return f
|
|
|
|
t_ignore = "\t "
|
|
|
|
# C or C++ comment (ignore)
|
|
def t_c_comment(self, t):
|
|
r"/\*(.|\n)*?\*/"
|
|
t.lexer.lineno += t.value.count("\n")
|
|
|
|
def t_cpp_comment(self, t):
|
|
r"//.*"
|
|
|
|
# Define a rule so we can track line numbers
|
|
def t_newline(self, t):
|
|
r"\n+"
|
|
t.lexer.lineno += len(t.value)
|
|
|
|
reserved = {
|
|
"protocol": "PROTOCOL",
|
|
"include": "INCLUDE",
|
|
"global": "GLOBAL",
|
|
"machine": "MACHINE",
|
|
"in_port": "IN_PORT",
|
|
"out_port": "OUT_PORT",
|
|
"action": "ACTION",
|
|
"transition": "TRANS",
|
|
"structure": "STRUCT",
|
|
"external_type": "EXTERN_TYPE",
|
|
"enumeration": "ENUM",
|
|
"state_declaration": "STATE_DECL",
|
|
"peek": "PEEK",
|
|
"stall_and_wait": "STALL_AND_WAIT",
|
|
"wakeup_port": "WAKEUP_PORT",
|
|
"enqueue": "ENQUEUE",
|
|
"check_allocate": "CHECK_ALLOCATE",
|
|
"check_next_cycle": "CHECK_NEXT_CYCLE",
|
|
"check_stop_slots": "CHECK_STOP_SLOTS",
|
|
"check_on_cache_probe": "CHECK_PROBE",
|
|
"static_cast": "STATIC_CAST",
|
|
"if": "IF",
|
|
"is_valid": "IS_VALID",
|
|
"is_invalid": "IS_INVALID",
|
|
"else": "ELSE",
|
|
"return": "RETURN",
|
|
"void": "VOID",
|
|
"new": "NEW",
|
|
"OOD": "OOD",
|
|
"defer_enqueueing": "DEFER_ENQUEUEING",
|
|
}
|
|
|
|
literals = ":[]{}(),="
|
|
|
|
tokens = [
|
|
"EQ",
|
|
"NE",
|
|
"LT",
|
|
"GT",
|
|
"LE",
|
|
"GE",
|
|
"LEFTSHIFT",
|
|
"RIGHTSHIFT",
|
|
"NOT",
|
|
"AND",
|
|
"OR",
|
|
"PLUS",
|
|
"DASH",
|
|
"STAR",
|
|
"SLASH",
|
|
"MOD",
|
|
"INCR",
|
|
"DECR",
|
|
"DOUBLE_COLON",
|
|
"SEMI",
|
|
"ASSIGN",
|
|
"DOT",
|
|
"IDENT",
|
|
"LIT_BOOL",
|
|
"FLOATNUMBER",
|
|
"NUMBER",
|
|
"STRING",
|
|
"AMP",
|
|
"CONST",
|
|
]
|
|
tokens += reserved.values()
|
|
|
|
t_EQ = r"=="
|
|
t_NE = r"!="
|
|
t_LT = r"<"
|
|
t_GT = r">"
|
|
t_LE = r"<="
|
|
t_GE = r">="
|
|
t_LEFTSHIFT = r"<<"
|
|
t_RIGHTSHIFT = r">>"
|
|
t_NOT = r"!"
|
|
t_AND = r"&&"
|
|
t_OR = r"\|\|"
|
|
t_PLUS = r"\+"
|
|
t_DASH = r"-"
|
|
t_STAR = r"\*"
|
|
t_AMP = r"&"
|
|
t_CONST = r"const"
|
|
t_SLASH = r"/"
|
|
t_MOD = r"%"
|
|
t_DOUBLE_COLON = r"::"
|
|
t_SEMI = r";"
|
|
t_ASSIGN = r":="
|
|
t_DOT = r"\."
|
|
t_INCR = r"\+\+"
|
|
t_DECR = r"--"
|
|
|
|
precedence = (
|
|
("left", "INCR", "DECR"),
|
|
("left", "OR"),
|
|
("left", "AND"),
|
|
("left", "EQ", "NE"),
|
|
("left", "LT", "GT", "LE", "GE"),
|
|
("left", "RIGHTSHIFT", "LEFTSHIFT"),
|
|
("left", "PLUS", "DASH"),
|
|
("left", "STAR", "SLASH", "MOD"),
|
|
("right", "NOT", "UMINUS"),
|
|
)
|
|
|
|
def t_IDENT(self, t):
|
|
r"[a-zA-Z_][a-zA-Z_0-9]*"
|
|
if t.value == "true":
|
|
t.type = "LIT_BOOL"
|
|
t.value = True
|
|
return t
|
|
|
|
if t.value == "false":
|
|
t.type = "LIT_BOOL"
|
|
t.value = False
|
|
return t
|
|
|
|
# Check for reserved words
|
|
t.type = self.reserved.get(t.value, "IDENT")
|
|
return t
|
|
|
|
def t_FLOATNUMBER(self, t):
|
|
"[0-9]+[.][0-9]+"
|
|
try:
|
|
t.value = float(t.value)
|
|
except ValueError:
|
|
raise ParseError("Illegal float", t)
|
|
return t
|
|
|
|
def t_NUMBER(self, t):
|
|
r"[0-9]+"
|
|
try:
|
|
t.value = int(t.value)
|
|
except ValueError:
|
|
raise ParseError("Illegal number", t)
|
|
return t
|
|
|
|
def t_STRING1(self, t):
|
|
r'\"[^"\n]*\"'
|
|
t.type = "STRING"
|
|
t.value = t.value[1:-1]
|
|
return t
|
|
|
|
def t_STRING2(self, t):
|
|
r"\'[^'\n]*\'"
|
|
t.type = "STRING"
|
|
t.value = t.value[1:-1]
|
|
return t
|
|
|
|
def p_file(self, p):
|
|
"file : decls"
|
|
p[0] = p[1]
|
|
|
|
def p_empty(self, p):
|
|
"empty :"
|
|
|
|
def p_decls(self, p):
|
|
"decls : declsx"
|
|
p[0] = ast.DeclListAST(self, p[1])
|
|
|
|
def p_declsx__list(self, p):
|
|
"declsx : decl declsx"
|
|
if isinstance(p[1], ast.DeclListAST):
|
|
decls = p[1].decls
|
|
elif p[1] is None:
|
|
decls = []
|
|
else:
|
|
decls = [p[1]]
|
|
p[0] = decls + p[2]
|
|
|
|
def p_declsx__none(self, p):
|
|
"declsx : empty"
|
|
p[0] = []
|
|
|
|
def p_decl__protocol(self, p):
|
|
"decl : PROTOCOL STRING exprs SEMI"
|
|
if self.protocol:
|
|
msg = "Protocol can only be set once! Error at {}:{}\n".format(
|
|
self.current_source,
|
|
self.current_line,
|
|
)
|
|
raise ParseError(msg)
|
|
self.protocol = p[2]
|
|
# Check for options
|
|
for option in p[3]:
|
|
assert type(option) is ast.VarExprAST
|
|
if option.name in self.options:
|
|
self.options[option.name] = True
|
|
else:
|
|
raise ParseError(
|
|
f"Unknown option '{option.name}' for protocol "
|
|
f"at {self.current_source}:{self.current_line}"
|
|
)
|
|
p[0] = None
|
|
|
|
def p_decl__include(self, p):
|
|
"decl : INCLUDE STRING SEMI"
|
|
dirname = os.path.dirname(self.current_source)
|
|
if os.path.exists(os.path.join(dirname, p[2])):
|
|
filename = os.path.join(dirname, p[2])
|
|
else:
|
|
filename = os.path.join(self.base_dir, p[2])
|
|
p[0] = self.parse_file(filename)
|
|
|
|
def p_decl__machine0(self, p):
|
|
"decl : MACHINE '(' enumeration ')' ':' obj_decls '{' decls '}'"
|
|
p[0] = ast.MachineAST(self, p[3], [], p[7], p[9])
|
|
|
|
def p_decl__machine1(self, p):
|
|
"decl : MACHINE '(' enumeration pairs ')' ':' obj_decls '{' decls '}'"
|
|
p[0] = ast.MachineAST(self, p[3], p[4], p[7], p[9])
|
|
|
|
def p_decl__action(self, p):
|
|
"decl : ACTION '(' ident pairs ')' statements"
|
|
p[0] = ast.ActionDeclAST(self, p[3], p[4], p[6])
|
|
|
|
def p_decl__in_port(self, p):
|
|
"decl : IN_PORT '(' ident ',' type ',' var pairs ')' statements"
|
|
p[0] = ast.InPortDeclAST(self, p[3], p[5], p[7], p[8], p[10])
|
|
|
|
def p_decl__out_port(self, p):
|
|
"decl : OUT_PORT '(' ident ',' type ',' var pairs ')' SEMI"
|
|
p[0] = ast.OutPortDeclAST(self, p[3], p[5], p[7], p[8])
|
|
|
|
def p_decl__trans0(self, p):
|
|
"decl : TRANS '(' idents ',' idents ',' ident_or_star ')' idents"
|
|
p[0] = ast.TransitionDeclAST(self, [], p[3], p[5], p[7], p[9])
|
|
|
|
def p_decl__trans1(self, p):
|
|
"decl : TRANS '(' idents ',' idents ')' idents"
|
|
p[0] = ast.TransitionDeclAST(self, [], p[3], p[5], None, p[7])
|
|
|
|
def p_decl__trans2(self, p):
|
|
"decl : TRANS '(' idents ',' idents ',' ident_or_star ')' idents idents"
|
|
p[0] = ast.TransitionDeclAST(self, p[9], p[3], p[5], p[7], p[10])
|
|
|
|
def p_decl__trans3(self, p):
|
|
"decl : TRANS '(' idents ',' idents ')' idents idents"
|
|
p[0] = ast.TransitionDeclAST(self, p[7], p[3], p[5], None, p[8])
|
|
|
|
def p_decl__extern0(self, p):
|
|
"decl : EXTERN_TYPE '(' type pairs ')' SEMI"
|
|
p[4]["external"] = "yes"
|
|
p[0] = ast.TypeDeclAST(self, p[3], p[4], [])
|
|
|
|
def p_decl__global(self, p):
|
|
"decl : GLOBAL '(' type pairs ')' '{' type_members '}'"
|
|
p[4]["global"] = "yes"
|
|
p[0] = ast.TypeDeclAST(self, p[3], p[4], p[7])
|
|
|
|
def p_decl__struct(self, p):
|
|
"decl : STRUCT '(' type pairs ')' '{' type_members '}'"
|
|
p[0] = ast.TypeDeclAST(self, p[3], p[4], p[7])
|
|
|
|
def p_decl__enum(self, p):
|
|
"decl : ENUM '(' type pairs ')' '{' type_enums '}'"
|
|
p[4]["enumeration"] = "yes"
|
|
p[0] = ast.EnumDeclAST(self, p[3], p[4], p[7])
|
|
|
|
def p_decl__state_decl(self, p):
|
|
"decl : STATE_DECL '(' type pairs ')' '{' type_states '}'"
|
|
p[4]["enumeration"] = "yes"
|
|
p[4]["state_decl"] = "yes"
|
|
p[0] = ast.StateDeclAST(self, p[3], p[4], p[7])
|
|
|
|
# Type fields
|
|
def p_obj_decls__list(self, p):
|
|
"obj_decls : obj_decl obj_decls"
|
|
p[0] = [p[1]] + p[2]
|
|
|
|
def p_obj_decls__empty(self, p):
|
|
"obj_decls : empty"
|
|
p[0] = []
|
|
|
|
def p_type_members__list(self, p):
|
|
"type_members : type_member type_members"
|
|
p[0] = [p[1]] + p[2]
|
|
|
|
def p_type_members__empty(self, p):
|
|
"type_members : empty"
|
|
p[0] = []
|
|
|
|
def p_type_member__0(self, p):
|
|
"""type_member : obj_decl
|
|
| func_decl
|
|
| func_def"""
|
|
p[0] = p[1]
|
|
|
|
# Member / Variable declarations
|
|
def p_decl__obj_decl(self, p):
|
|
"decl : obj_decl"
|
|
p[0] = p[1]
|
|
|
|
def p_obj_decl__0(self, p):
|
|
"obj_decl : type ident pairs SEMI"
|
|
p[0] = ast.ObjDeclAST(self, p[1], p[2], p[3], None, False)
|
|
|
|
def p_obj_decl__1(self, p):
|
|
"obj_decl : type STAR ident pairs SEMI"
|
|
p[0] = ast.ObjDeclAST(self, p[1], p[3], p[4], None, True)
|
|
|
|
def p_obj_decl__2(self, p):
|
|
"obj_decl : type ident ASSIGN expr SEMI"
|
|
p[0] = ast.ObjDeclAST(
|
|
self, p[1], p[2], ast.PairListAST(self), p[4], False
|
|
)
|
|
|
|
def p_obj_decl__3(self, p):
|
|
"obj_decl : type STAR ident ASSIGN expr SEMI"
|
|
p[0] = ast.ObjDeclAST(
|
|
self, p[1], p[3], ast.PairListAST(self), p[5], True
|
|
)
|
|
|
|
# Function definition and declaration
|
|
def p_decl__func_decl(self, p):
|
|
"decl : func_decl"
|
|
p[0] = p[1]
|
|
|
|
def p_func_decl__0(self, p):
|
|
"""func_decl : void ident '(' params ')' pairs SEMI
|
|
| type ident '(' params ')' pairs SEMI"""
|
|
p[0] = ast.FuncDeclAST(self, p[1], p[2], p[4], p[6], None)
|
|
|
|
def p_func_decl__1(self, p):
|
|
"""func_decl : void ident '(' types ')' pairs SEMI
|
|
| type ident '(' types ')' pairs SEMI"""
|
|
p[0] = ast.FuncDeclAST(self, p[1], p[2], p[4], p[6], None)
|
|
|
|
def p_decl__func_def(self, p):
|
|
"decl : func_def"
|
|
p[0] = p[1]
|
|
|
|
def p_func_def__0(self, p):
|
|
"""func_def : void ident '(' params ')' pairs statements
|
|
| type ident '(' params ')' pairs statements"""
|
|
p[0] = ast.FuncDeclAST(self, p[1], p[2], p[4], p[6], p[7])
|
|
|
|
# Enum fields
|
|
def p_type_enums__list(self, p):
|
|
"type_enums : type_enum type_enums"
|
|
p[0] = [p[1]] + p[2]
|
|
|
|
def p_type_enums__empty(self, p):
|
|
"type_enums : empty"
|
|
p[0] = []
|
|
|
|
def p_type_enum(self, p):
|
|
"type_enum : ident pairs SEMI"
|
|
p[0] = ast.TypeFieldEnumAST(self, p[1], p[2])
|
|
|
|
# States
|
|
def p_type_states__list(self, p):
|
|
"type_states : type_state type_states"
|
|
p[0] = [p[1]] + p[2]
|
|
|
|
def p_type_states__empty(self, p):
|
|
"type_states : empty"
|
|
p[0] = []
|
|
|
|
def p_type_state(self, p):
|
|
"type_state : ident ',' enumeration pairs SEMI"
|
|
p[0] = ast.TypeFieldStateAST(self, p[1], p[3], p[4])
|
|
|
|
# Formal Param
|
|
def p_params__many(self, p):
|
|
"params : param ',' params"
|
|
p[0] = [p[1]] + p[3]
|
|
|
|
def p_params__one(self, p):
|
|
"params : param"
|
|
p[0] = [p[1]]
|
|
|
|
def p_params__none(self, p):
|
|
"params : empty"
|
|
p[0] = []
|
|
|
|
def p_param(self, p):
|
|
"param : type ident"
|
|
p[0] = ast.FormalParamAST(self, p[1], p[2])
|
|
|
|
def p_param__pointer(self, p):
|
|
"param : type STAR ident"
|
|
p[0] = ast.FormalParamAST(self, p[1], p[3], None, "PTR")
|
|
|
|
def p_param__ref(self, p):
|
|
"param : type AMP ident"
|
|
p[0] = ast.FormalParamAST(self, p[1], p[3], None, "REF")
|
|
|
|
def p_param__const_ref(self, p):
|
|
"param : CONST type AMP ident"
|
|
p[0] = ast.FormalParamAST(self, p[1], p[3], None, "CONST_REF")
|
|
|
|
def p_param__pointer_default(self, p):
|
|
"param : type STAR ident ASSIGN STRING"
|
|
p[0] = ast.FormalParamAST(self, p[1], p[3], p[5], "PTR")
|
|
|
|
def p_param__default_number(self, p):
|
|
"param : type ident ASSIGN NUMBER"
|
|
p[0] = ast.FormalParamAST(self, p[1], p[2], p[4])
|
|
|
|
def p_param__default_bool(self, p):
|
|
"param : type ident ASSIGN LIT_BOOL"
|
|
p[0] = ast.FormalParamAST(self, p[1], p[2], p[4])
|
|
|
|
def p_param__default_string(self, p):
|
|
"param : type ident ASSIGN STRING"
|
|
p[0] = ast.FormalParamAST(self, p[1], p[2], p[4])
|
|
|
|
# Type
|
|
def p_types__multiple(self, p):
|
|
"types : type ',' types"
|
|
p[0] = [p[1]] + p[3]
|
|
|
|
def p_types__one(self, p):
|
|
"types : type"
|
|
p[0] = [p[1]]
|
|
|
|
def p_types__empty(self, p):
|
|
"types : empty"
|
|
p[0] = []
|
|
|
|
def p_typestr__multi(self, p):
|
|
"typestr : typestr DOUBLE_COLON ident"
|
|
p[0] = f"{p[1]}::{p[3]}"
|
|
|
|
def p_typestr__single(self, p):
|
|
"typestr : ident"
|
|
p[0] = p[1]
|
|
|
|
def p_type__one(self, p):
|
|
"type : typestr"
|
|
p[0] = ast.TypeAST(self, p[1])
|
|
|
|
def p_void(self, p):
|
|
"void : VOID"
|
|
p[0] = ast.TypeAST(self, p[1])
|
|
|
|
# Idents and lists
|
|
def p_idents__braced(self, p):
|
|
"idents : '{' identx '}'"
|
|
p[0] = p[2]
|
|
|
|
def p_idents__bare(self, p):
|
|
"idents : ident"
|
|
p[0] = [p[1]]
|
|
|
|
def p_identx__multiple_1(self, p):
|
|
"""identx : ident SEMI identx
|
|
| ident ',' identx"""
|
|
p[0] = [p[1]] + p[3]
|
|
|
|
def p_identx__multiple_2(self, p):
|
|
"identx : ident identx"
|
|
p[0] = [p[1]] + p[2]
|
|
|
|
def p_identx__single(self, p):
|
|
"identx : empty"
|
|
p[0] = []
|
|
|
|
def p_ident(self, p):
|
|
"ident : IDENT"
|
|
p[0] = p[1]
|
|
|
|
def p_ident_or_star(self, p):
|
|
"""ident_or_star : ident
|
|
| STAR"""
|
|
p[0] = p[1]
|
|
|
|
# Pair and pair lists
|
|
def p_pairs__list(self, p):
|
|
"pairs : ',' pairsx"
|
|
p[0] = p[2]
|
|
|
|
def p_pairs__empty(self, p):
|
|
"pairs : empty"
|
|
p[0] = ast.PairListAST(self)
|
|
|
|
def p_pairsx__many(self, p):
|
|
"pairsx : pair ',' pairsx"
|
|
p[0] = p[3]
|
|
p[0].addPair(p[1])
|
|
|
|
def p_pairsx__one(self, p):
|
|
"pairsx : pair"
|
|
p[0] = ast.PairListAST(self)
|
|
p[0].addPair(p[1])
|
|
|
|
def p_pair__assign(self, p):
|
|
"""pair : ident '=' STRING
|
|
| ident '=' ident
|
|
| ident '=' NUMBER"""
|
|
p[0] = ast.PairAST(self, p[1], p[3])
|
|
|
|
def p_pair__literal(self, p):
|
|
"pair : STRING"
|
|
p[0] = ast.PairAST(self, "short", p[1])
|
|
|
|
# Below are the rules for action descriptions
|
|
def p_statements__inner(self, p):
|
|
"statements : '{' statements_inner '}'"
|
|
p[0] = ast.StatementListAST(self, p[2])
|
|
|
|
def p_statements__none(self, p):
|
|
"statements : '{' '}'"
|
|
p[0] = ast.StatementListAST(self, [])
|
|
|
|
def p_statements_inner__many(self, p):
|
|
"statements_inner : statement statements_inner"
|
|
p[0] = [p[1]] + p[2]
|
|
|
|
def p_statements_inner__one(self, p):
|
|
"statements_inner : statement"
|
|
p[0] = [p[1]]
|
|
|
|
def p_exprs__multiple(self, p):
|
|
"exprs : expr ',' exprs"
|
|
p[0] = [p[1]] + p[3]
|
|
|
|
def p_exprs__one(self, p):
|
|
"exprs : expr"
|
|
p[0] = [p[1]]
|
|
|
|
def p_exprs__empty(self, p):
|
|
"exprs : empty" ""
|
|
p[0] = []
|
|
|
|
def p_statement__expression(self, p):
|
|
"statement : expr SEMI"
|
|
p[0] = ast.ExprStatementAST(self, p[1])
|
|
|
|
def p_statement__assign(self, p):
|
|
"statement : expr ASSIGN expr SEMI"
|
|
p[0] = ast.AssignStatementAST(self, p[1], p[3])
|
|
|
|
def p_statement__enqueue(self, p):
|
|
"statement : ENQUEUE '(' var ',' type ')' statements"
|
|
p[0] = ast.EnqueueStatementAST(self, p[3], p[5], None, None, p[7])
|
|
|
|
def p_statement__enqueue_latency(self, p):
|
|
"statement : ENQUEUE '(' var ',' type ',' expr ')' statements"
|
|
p[0] = ast.EnqueueStatementAST(self, p[3], p[5], p[7], None, p[9])
|
|
|
|
def p_statement__enqueue_latency_bypass_strict_fifo(self, p):
|
|
"statement : ENQUEUE '(' var ',' type ',' expr ',' expr ')' statements"
|
|
p[0] = ast.EnqueueStatementAST(self, p[3], p[5], p[7], p[9], p[11])
|
|
|
|
def p_statement__defer_enqueueing(self, p):
|
|
"statement : DEFER_ENQUEUEING '(' var ',' type ')' statements"
|
|
p[0] = ast.DeferEnqueueingStatementAST(self, p[3], p[5], p[7])
|
|
|
|
def p_statement__stall_and_wait(self, p):
|
|
"statement : STALL_AND_WAIT '(' var ',' var ')' SEMI"
|
|
p[0] = ast.StallAndWaitStatementAST(self, p[3], p[5])
|
|
|
|
def p_statement__wakeup_port(self, p):
|
|
"statement : WAKEUP_PORT '(' var ',' var ')' SEMI"
|
|
p[0] = ast.WakeupPortStatementAST(self, p[3], p[5])
|
|
|
|
def p_statement__peek(self, p):
|
|
"statement : PEEK '(' var ',' type pairs ')' statements"
|
|
p[0] = ast.PeekStatementAST(self, p[3], p[5], p[6], p[8], "peek")
|
|
|
|
def p_statement__check_allocate(self, p):
|
|
"statement : CHECK_ALLOCATE '(' var ')' SEMI"
|
|
p[0] = ast.CheckAllocateStatementAST(self, p[3])
|
|
|
|
def p_statement__check_next_cycle(self, p):
|
|
"statement : CHECK_NEXT_CYCLE '(' ')' SEMI"
|
|
p[0] = ast.CheckNextCycleAST(self)
|
|
|
|
def p_statement__check_stop(self, p):
|
|
"statement : CHECK_STOP_SLOTS '(' var ',' STRING ',' STRING ')' SEMI"
|
|
p[0] = ast.CheckStopStatementAST(self, p[3], p[5], p[7])
|
|
|
|
def p_statement__check_probe(self, p):
|
|
"statement : CHECK_PROBE '(' var ',' var ')' SEMI"
|
|
p[0] = ast.CheckProbeStatementAST(self, p[3], p[5])
|
|
|
|
def p_statement__return(self, p):
|
|
"statement : RETURN expr SEMI"
|
|
p[0] = ast.ReturnStatementAST(self, p[2])
|
|
|
|
def p_statement__if(self, p):
|
|
"statement : if_statement"
|
|
p[0] = p[1]
|
|
|
|
def p_if_statement__if(self, p):
|
|
"if_statement : IF '(' expr ')' statements"
|
|
p[0] = ast.IfStatementAST(self, p[3], p[5], None)
|
|
|
|
def p_if_statement__if_else(self, p):
|
|
"if_statement : IF '(' expr ')' statements ELSE statements"
|
|
p[0] = ast.IfStatementAST(self, p[3], p[5], p[7])
|
|
|
|
def p_statement__if_else_if(self, p):
|
|
"if_statement : IF '(' expr ')' statements ELSE if_statement"
|
|
p[0] = ast.IfStatementAST(
|
|
self, p[3], p[5], ast.StatementListAST(self, p[7])
|
|
)
|
|
|
|
def p_expr__static_cast(self, p):
|
|
"aexpr : STATIC_CAST '(' type ',' expr ')'"
|
|
p[0] = ast.StaticCastAST(self, p[3], "ref", p[5])
|
|
|
|
def p_expr__static_cast_ptr(self, p):
|
|
"aexpr : STATIC_CAST '(' type ',' STRING ',' expr ')'"
|
|
p[0] = ast.StaticCastAST(self, p[3], p[5], p[7])
|
|
|
|
def p_expr__var(self, p):
|
|
"aexpr : var"
|
|
p[0] = p[1]
|
|
|
|
def p_expr__localvar(self, p):
|
|
"aexpr : type ident"
|
|
p[0] = ast.LocalVariableAST(self, p[1], p[2])
|
|
|
|
def p_expr__literal(self, p):
|
|
"aexpr : literal"
|
|
p[0] = p[1]
|
|
|
|
def p_expr__enumeration(self, p):
|
|
"aexpr : enumeration"
|
|
p[0] = p[1]
|
|
|
|
def p_expr__func_call(self, p):
|
|
"aexpr : ident '(' exprs ')'"
|
|
p[0] = ast.FuncCallExprAST(self, p[1], p[3])
|
|
|
|
def p_expr__new(self, p):
|
|
"aexpr : NEW type"
|
|
p[0] = ast.NewExprAST(self, p[2])
|
|
|
|
def p_expr__null(self, p):
|
|
"aexpr : OOD"
|
|
p[0] = ast.OodAST(self)
|
|
|
|
def p_expr__member(self, p):
|
|
"aexpr : aexpr DOT ident"
|
|
p[0] = ast.MemberExprAST(self, p[1], p[3])
|
|
|
|
def p_expr__member_method_call(self, p):
|
|
"aexpr : aexpr DOT ident '(' exprs ')'"
|
|
p[0] = ast.MemberMethodCallExprAST(
|
|
self, p[1], ast.FuncCallExprAST(self, p[3], p[5])
|
|
)
|
|
|
|
def p_expr__member_method_call_lookup(self, p):
|
|
"aexpr : aexpr '[' exprs ']'"
|
|
p[0] = ast.MemberMethodCallExprAST(
|
|
self, p[1], ast.FuncCallExprAST(self, "lookup", p[3])
|
|
)
|
|
|
|
def p_expr__class_method_call(self, p):
|
|
"aexpr : type DOUBLE_COLON ident '(' exprs ')'"
|
|
p[0] = ast.ClassMethodCallExprAST(
|
|
self, p[1], ast.FuncCallExprAST(self, p[3], p[5])
|
|
)
|
|
|
|
def p_expr__aexpr(self, p):
|
|
"expr : aexpr"
|
|
p[0] = p[1]
|
|
|
|
def p_expr__binary_op(self, p):
|
|
"""expr : expr STAR expr
|
|
| expr SLASH expr
|
|
| expr MOD expr
|
|
| expr PLUS expr
|
|
| expr DASH expr
|
|
| expr LT expr
|
|
| expr GT expr
|
|
| expr LE expr
|
|
| expr GE expr
|
|
| expr EQ expr
|
|
| expr NE expr
|
|
| expr AND expr
|
|
| expr OR expr
|
|
| expr RIGHTSHIFT expr
|
|
| expr LEFTSHIFT expr"""
|
|
p[0] = ast.InfixOperatorExprAST(self, p[1], p[2], p[3])
|
|
|
|
# FIXME - unary not
|
|
def p_expr__unary_op(self, p):
|
|
"""expr : NOT expr
|
|
| INCR expr
|
|
| DECR expr
|
|
| DASH expr %prec UMINUS"""
|
|
p[0] = ast.PrefixOperatorExprAST(self, p[1], p[2])
|
|
|
|
def p_expr__parens(self, p):
|
|
"aexpr : '(' expr ')'"
|
|
p[0] = p[2]
|
|
|
|
def p_expr__is_valid_ptr(self, p):
|
|
"aexpr : IS_VALID '(' expr ')'"
|
|
p[0] = ast.IsValidPtrExprAST(self, p[3], True)
|
|
|
|
def p_expr__is_invalid_ptr(self, p):
|
|
"aexpr : IS_INVALID '(' expr ')'"
|
|
p[0] = ast.IsValidPtrExprAST(self, p[3], False)
|
|
|
|
def p_literal__string(self, p):
|
|
"literal : STRING"
|
|
p[0] = ast.LiteralExprAST(self, p[1], "std::string")
|
|
|
|
def p_literal__number(self, p):
|
|
"literal : NUMBER"
|
|
p[0] = ast.LiteralExprAST(self, p[1], "int")
|
|
|
|
def p_literal__float(self, p):
|
|
"literal : FLOATNUMBER"
|
|
p[0] = ast.LiteralExprAST(self, p[1], "int")
|
|
|
|
def p_literal__bool(self, p):
|
|
"literal : LIT_BOOL"
|
|
p[0] = ast.LiteralExprAST(self, p[1], "bool")
|
|
|
|
def p_enumeration(self, p):
|
|
"enumeration : ident ':' ident"
|
|
p[0] = ast.EnumExprAST(self, ast.TypeAST(self, p[1]), p[3])
|
|
|
|
def p_var(self, p):
|
|
"var : ident"
|
|
p[0] = ast.VarExprAST(self, p[1])
|