# BLIFPARSER
This is a simple Python library that parses BLIF (Berkeley Logic Interchange Format) files (used by SIS, Sequential Interactive Synthesis).
> And also evalutes if some keyword's parameters have syntactically correct values.
Only the basic keywords are parsed (```.model```, ```.inputs```, ```.outputs```, ```.names```, all the FSM keywords, ```.latch```, ```.exdc```, ```.end```).
> More complex BLIF files with ```.clock```, ```.gate```, ```.mlatch```, ```.clock_event``` and delay constraits are only partially parsed.
>
> This is because the workflow I am supporting does not use these keywords
Currently only one ```.model``` keyword per file is supported.
> You can see this as a "feature" because it forces the use of a good practise: use many files, one per each component.
You can also use this library as a basic BLIF validator.
> Complex checks such as cross file definition checks and input-output names check are NOT implemented
> because the primary intent of this library is to parse BLIF files.
A more full/complex validator is in the works (and it will use this parser).
---
---
WARNING
This parser DOES NOT use grammar files NOR [PEG](https://en.wikipedia.org/wiki/Parsing_expression_grammar) for parsing blif files:
this means that the parsing could be "not perfect".
> If someone wants to contribute and change this feel free to make pull requests!
>
> If this library inspires you to write a better parser from scratch, please let me know by making a GH issue
This means that the library works because:
* the BLIF (format) is simple: most of the time parameters are on the same line of the keywords
* (some) unit and end to end tests were written
---
---
## Index
* [Requirements](#requirements)
* [Installation](#installation)
* [Usage](#usage)
* [Description](#description)
* [Changelog](#changelog)
* [Author](#author)
## Requirements
* python 3 (>= 3.7)
## Installation
First, install the library using PIP:
pip install blifparser
Then:
* if you want to use this library as a validation tool, check the "[As a validator tool](#as-a-validator-tool)" section
* if you want to use this library inside your software, check the "[As a library](#as-a-library)" section
> If this is the only way you want to use this software, you can also install it using the installer on the Github Release page
## Usage
## As a validator tool
Execute the script using this command:
blifparser <input_path>
You can also execute it this way:
python -m blifparser <input_path>
> Replace ```<input_path>``` with the path to the BLIF file to validate
When you have fixed the errors, execute the script until
you have fixed all the errors.
> Not all errors appear after the first script execution.
### As a library
Basic/common usage:
```py
# import the os library: useful to get the absolute path to the input file
import os
# import this library
import blifparser.blifparser as blifparser
# get the file path and pass it to the parser
filepath = os.path.abspath("example.blif")
parser = blifparser.BlifParser(filepath)
# get the object that contains the parsed data
# from the parser
blif = parser.blif
```
Now you can:
```py
# get the name of the model
print(blif.model.name)
# get the list of the inputs
print(blif.inputs.inputs)
# get the list of the outputs
print(blif.outputs.outputs)
# get the list of .search keyword
print(blif.imports)
# get the imported file name/path of the first .search keyword
first_import = blif.imports[0]
print(first_import.filepath)
# get the list of subcircuits (.subckt)
print(blif.subcircuits)
# get data from the first subcircuit definition
first_subcircuit = blif.subcircuits[0]
print(first_subcircuit.modelname) # name of the model
print(first_subcircuit.params) # subcircuit's parameters
# get the list of boolean functions (.names)
print(blif.booleanfunctions)
# get data from the first boolean function definition
first_boolfunc = blif.booleanfunctions[0]
print(first_boolfunc.inputs) # list with the names of the inputs
print(first_boolfunc.output) # string with the name of the output
print(first_boolfunc.truthtable) # list of lists (each row is a truth table row)
# get the dictionary with the number of occurrencies of each keyword
print(blif.nkeywords)
# get the list of problems/issues
print(blif.problems)
# get the list of the latches
print(blif.latches)
# get the data of the first latch
first_latch = blif.latches[0]
print(first_latch.input) # name of the input
print(first_latch.output) # name of the output
print(first_latch.type) # type of latch (like "re", ...)
print(first_latch.control) # clock name
print(first_latch.initval) # initial value
# get the data of the FSM (Finite State Machine)
print(blif.fsm.i.num) # number of inputs
print(blif.fsm.o.num) # number of outputs
print(blif.fsm.s.num) # number of states
print(blif.fsm.p.num) # number of state transitions
print(blif.fsm.r.name) # name of the reset state
print(blif.fsm.transtable) # list of lists (contains the transition table)
```
You can also obtain a networkx graph using the ```get_graph()``` method:
```python
# import the os library: useful to get the absolute path to the input file
import os
# import this library
import blifparser.blifparser as blifparser
# get the file path and pass it to the parser
filepath = os.path.abspath("example.blif")
parser = blifparser.BlifParser(filepath)
# generate the graph and memorize some statistics
graph_data = parser.get_graph()
# retrive networkx graph: can be used to export it as an image or customize it
nx_graph = graph_data.nx_graph
# extract nodes from the graph: each node has inputs, outputs, a type and the color that can be used to fill the node
# > by default .model inputs are red, .model outputs are blue, everything else is black
ext_nodes = [n for n in nx_graph.nodes]
# retrive the length of the longest label: can be used to determine the height of the graph exported onto an image
longest_label = nx_graph.longest_label
# retrive the size of the "item" node that has the most number of inputs: can be used to determine the width of the graph exported onto an image
# > where "item" is .inputs/.outputs/.names/.subckt/.latch
max_inputs = nx_graph.max_inputs
```
## Description
These are the first steps to use this library:
```py
# import the os library: useful to get the absolute path to the input file
import os
# import this library
import blifparser.blifparser as blifparser
# get the file path and pass it to the parser
filepath = os.path.abspath("example.blif")
parser = blifparser.BlifParser(filepath)
# get the object that contains the parsed data
# from the parser
blif = parser.blif
# get an object that contains a networkx graph of the blif file and memorize some statistics
graph_data = parser.get_graph()
```
The ```blifparser.BlifParser()``` object is the parser:
it prepares the file for parsing using the ```prepare_file()``` method
and then creates a ```keywords.generic.Blif()``` object that will contain
all the information parsed from the file.
> The ```prepare_file()``` method copies the file and
> then removes (on the copy):
> * the newlines made with the backslash "```\```"
> * the comments made with "```#```".
Then each line is read and parsed:
* if the line contains a keyword, a "keyword" object is created and then
"linked" to the ```keywords.generic.Blif()``` object (its parameters get parsed with the keyword)
> For example: if a ```.model``` keyword is found, a ```keywords.generic.Model()``` object
> gets created and set in the ```keywords.generic.Blif()``` object. (```keywords.generic.Blif().model```)
* if the line contains text and the line comes after the ```.names``` keyword
it is interpreted as the truth table of the latest boolean function (defined by ```.names```)
> This behavior stops when the next keyword is found
* if the line contains text and the line comes after the ```.start_kiss``` keyword
it is interpreted as the transition table of the Finite State Machine.
> This behavior stops when the next keyword is found
* If an unexpected text/keyword is found a "problem" or issue is collected inside the ```keywords.generic.Blif().problems``` list.
At the end of the parsing:
* if an FSM was found, a validation step checks if it is syntactically correct
* if some boolean functions were found, a validation step checks if they are syntactically correct
> The other validation steps are executed during object definition
Now you can use the ```blif``` object to get the parsed data
> Check the "Usage > [As a library](#as-a-library)" section for more details
## Changelog
**2022-12-12 2.0.0**:
* Added ```get_graph()``` method to the ```BlifParser``` class: generates and returns an object containing a networkx graph with inputs, outputs, latches, subckts and boolean functions connected together.
> This object also contains statistics which can be used when exporting the graph to an image file to roughly determine the dimensions of the image.
* Dropped python < 3.7 support.
**2021-04-23 1.0.0**:
First commit
## Author
[Zenaro Stefano (mario33881)](https://github.com/mario33881)
Raw data
{
"_id": null,
"home_page": "https://github.com/mario33881/blifparser",
"name": "blifparser",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": "",
"keywords": "SIS,BLIF,parser,development",
"author": "Zenaro Stefano (mario33881)",
"author_email": "mariortgasd@hotmail.com",
"download_url": "https://files.pythonhosted.org/packages/06/5a/160a94a2c37112326f3ec632c6800deb6ddcca35b231ea7711ccbe253fc3/blifparser-2.0.0.tar.gz",
"platform": null,
"description": "# BLIFPARSER\r\n\r\nThis is a simple Python library that parses BLIF (Berkeley Logic Interchange Format) files (used by SIS, Sequential Interactive Synthesis).\r\n> And also evalutes if some keyword's parameters have syntactically correct values.\r\n\r\nOnly the basic keywords are parsed (```.model```, ```.inputs```, ```.outputs```, ```.names```, all the FSM keywords, ```.latch```, ```.exdc```, ```.end```).\r\n> More complex BLIF files with ```.clock```, ```.gate```, ```.mlatch```, ```.clock_event``` and delay constraits are only partially parsed.\r\n>\r\n> This is because the workflow I am supporting does not use these keywords\r\n\r\nCurrently only one ```.model``` keyword per file is supported.\r\n> You can see this as a \"feature\" because it forces the use of a good practise: use many files, one per each component.\r\n\r\nYou can also use this library as a basic BLIF validator.\r\n> Complex checks such as cross file definition checks and input-output names check are NOT implemented\r\n> because the primary intent of this library is to parse BLIF files.\r\n\r\nA more full/complex validator is in the works (and it will use this parser).\r\n\r\n---\r\n---\r\n\r\nWARNING\r\n\r\nThis parser DOES NOT use grammar files NOR [PEG](https://en.wikipedia.org/wiki/Parsing_expression_grammar) for parsing blif files:\r\n\r\nthis means that the parsing could be \"not perfect\".\r\n> If someone wants to contribute and change this feel free to make pull requests!\r\n>\r\n> If this library inspires you to write a better parser from scratch, please let me know by making a GH issue\r\n\r\nThis means that the library works because:\r\n* the BLIF (format) is simple: most of the time parameters are on the same line of the keywords\r\n* (some) unit and end to end tests were written\r\n\r\n---\r\n---\r\n\r\n## Index\r\n\r\n* [Requirements](#requirements)\r\n* [Installation](#installation)\r\n* [Usage](#usage)\r\n* [Description](#description)\r\n* [Changelog](#changelog)\r\n* [Author](#author)\r\n\r\n## Requirements\r\n* python 3 (>= 3.7)\r\n\r\n## Installation\r\n\r\nFirst, install the library using PIP:\r\n\r\n pip install blifparser\r\n\r\nThen:\r\n* if you want to use this library as a validation tool, check the \"[As a validator tool](#as-a-validator-tool)\" section\r\n\r\n* if you want to use this library inside your software, check the \"[As a library](#as-a-library)\" section\r\n > If this is the only way you want to use this software, you can also install it using the installer on the Github Release page\r\n\r\n## Usage\r\n\r\n## As a validator tool\r\n\r\nExecute the script using this command:\r\n\r\n blifparser <input_path>\r\n\r\nYou can also execute it this way:\r\n\r\n python -m blifparser <input_path>\r\n\r\n> Replace ```<input_path>``` with the path to the BLIF file to validate\r\n\r\nWhen you have fixed the errors, execute the script until\r\nyou have fixed all the errors.\r\n> Not all errors appear after the first script execution.\r\n\r\n### As a library\r\n\r\nBasic/common usage:\r\n```py\r\n# import the os library: useful to get the absolute path to the input file\r\nimport os\r\n# import this library\r\nimport blifparser.blifparser as blifparser\r\n\r\n# get the file path and pass it to the parser\r\nfilepath = os.path.abspath(\"example.blif\")\r\nparser = blifparser.BlifParser(filepath)\r\n\r\n# get the object that contains the parsed data\r\n# from the parser\r\nblif = parser.blif\r\n```\r\n\r\nNow you can:\r\n\r\n```py\r\n# get the name of the model\r\nprint(blif.model.name)\r\n\r\n# get the list of the inputs\r\nprint(blif.inputs.inputs)\r\n\r\n# get the list of the outputs\r\nprint(blif.outputs.outputs)\r\n\r\n# get the list of .search keyword\r\nprint(blif.imports)\r\n\r\n# get the imported file name/path of the first .search keyword\r\nfirst_import = blif.imports[0]\r\nprint(first_import.filepath)\r\n\r\n# get the list of subcircuits (.subckt)\r\nprint(blif.subcircuits)\r\n\r\n# get data from the first subcircuit definition\r\nfirst_subcircuit = blif.subcircuits[0]\r\nprint(first_subcircuit.modelname) # name of the model\r\nprint(first_subcircuit.params) # subcircuit's parameters\r\n\r\n# get the list of boolean functions (.names)\r\nprint(blif.booleanfunctions)\r\n\r\n# get data from the first boolean function definition\r\nfirst_boolfunc = blif.booleanfunctions[0]\r\nprint(first_boolfunc.inputs) # list with the names of the inputs\r\nprint(first_boolfunc.output) # string with the name of the output\r\nprint(first_boolfunc.truthtable) # list of lists (each row is a truth table row)\r\n\r\n# get the dictionary with the number of occurrencies of each keyword\r\nprint(blif.nkeywords)\r\n\r\n# get the list of problems/issues\r\nprint(blif.problems)\r\n\r\n# get the list of the latches\r\nprint(blif.latches)\r\n\r\n# get the data of the first latch\r\nfirst_latch = blif.latches[0]\r\nprint(first_latch.input) # name of the input\r\nprint(first_latch.output) # name of the output\r\nprint(first_latch.type) # type of latch (like \"re\", ...)\r\nprint(first_latch.control) # clock name\r\nprint(first_latch.initval) # initial value\r\n\r\n# get the data of the FSM (Finite State Machine)\r\nprint(blif.fsm.i.num) # number of inputs\r\nprint(blif.fsm.o.num) # number of outputs\r\nprint(blif.fsm.s.num) # number of states\r\nprint(blif.fsm.p.num) # number of state transitions\r\nprint(blif.fsm.r.name) # name of the reset state\r\nprint(blif.fsm.transtable) # list of lists (contains the transition table)\r\n```\r\n\r\nYou can also obtain a networkx graph using the ```get_graph()``` method:\r\n```python\r\n# import the os library: useful to get the absolute path to the input file\r\nimport os\r\n# import this library\r\nimport blifparser.blifparser as blifparser\r\n\r\n# get the file path and pass it to the parser\r\nfilepath = os.path.abspath(\"example.blif\")\r\nparser = blifparser.BlifParser(filepath)\r\n\r\n# generate the graph and memorize some statistics\r\ngraph_data = parser.get_graph()\r\n\r\n# retrive networkx graph: can be used to export it as an image or customize it\r\nnx_graph = graph_data.nx_graph\r\n\r\n# extract nodes from the graph: each node has inputs, outputs, a type and the color that can be used to fill the node\r\n# > by default .model inputs are red, .model outputs are blue, everything else is black\r\next_nodes = [n for n in nx_graph.nodes]\r\n\r\n# retrive the length of the longest label: can be used to determine the height of the graph exported onto an image\r\nlongest_label = nx_graph.longest_label\r\n\r\n# retrive the size of the \"item\" node that has the most number of inputs: can be used to determine the width of the graph exported onto an image\r\n# > where \"item\" is .inputs/.outputs/.names/.subckt/.latch\r\nmax_inputs = nx_graph.max_inputs\r\n```\r\n\r\n## Description\r\n\r\nThese are the first steps to use this library:\r\n```py\r\n# import the os library: useful to get the absolute path to the input file\r\nimport os\r\n# import this library\r\nimport blifparser.blifparser as blifparser\r\n\r\n# get the file path and pass it to the parser\r\nfilepath = os.path.abspath(\"example.blif\")\r\nparser = blifparser.BlifParser(filepath)\r\n\r\n# get the object that contains the parsed data\r\n# from the parser\r\nblif = parser.blif\r\n\r\n# get an object that contains a networkx graph of the blif file and memorize some statistics\r\ngraph_data = parser.get_graph()\r\n```\r\n\r\nThe ```blifparser.BlifParser()``` object is the parser:\r\nit prepares the file for parsing using the ```prepare_file()``` method\r\nand then creates a ```keywords.generic.Blif()``` object that will contain\r\nall the information parsed from the file.\r\n> The ```prepare_file()``` method copies the file and \r\n> then removes (on the copy): \r\n> * the newlines made with the backslash \"```\\```\"\r\n> * the comments made with \"```#```\".\r\n\r\nThen each line is read and parsed:\r\n* if the line contains a keyword, a \"keyword\" object is created and then\r\n \"linked\" to the ```keywords.generic.Blif()``` object (its parameters get parsed with the keyword)\r\n\r\n > For example: if a ```.model``` keyword is found, a ```keywords.generic.Model()``` object\r\n > gets created and set in the ```keywords.generic.Blif()``` object. (```keywords.generic.Blif().model```)\r\n\r\n* if the line contains text and the line comes after the ```.names``` keyword\r\n it is interpreted as the truth table of the latest boolean function (defined by ```.names```)\r\n \r\n > This behavior stops when the next keyword is found\r\n\r\n* if the line contains text and the line comes after the ```.start_kiss``` keyword\r\n it is interpreted as the transition table of the Finite State Machine.\r\n\r\n > This behavior stops when the next keyword is found\r\n\r\n* If an unexpected text/keyword is found a \"problem\" or issue is collected inside the ```keywords.generic.Blif().problems``` list.\r\n\r\nAt the end of the parsing:\r\n* if an FSM was found, a validation step checks if it is syntactically correct\r\n* if some boolean functions were found, a validation step checks if they are syntactically correct\r\n> The other validation steps are executed during object definition\r\n\r\nNow you can use the ```blif``` object to get the parsed data\r\n> Check the \"Usage > [As a library](#as-a-library)\" section for more details\r\n\r\n## Changelog\r\n\r\n**2022-12-12 2.0.0**:\r\n\r\n* Added ```get_graph()``` method to the ```BlifParser``` class: generates and returns an object containing a networkx graph with inputs, outputs, latches, subckts and boolean functions connected together.\r\n > This object also contains statistics which can be used when exporting the graph to an image file to roughly determine the dimensions of the image.\r\n\r\n* Dropped python < 3.7 support.\r\n\r\n**2021-04-23 1.0.0**:\r\n\r\nFirst commit\r\n\r\n## Author\r\n[Zenaro Stefano (mario33881)](https://github.com/mario33881)\r\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A simple BLIF parser",
"version": "2.0.0",
"split_keywords": [
"sis",
"blif",
"parser",
"development"
],
"urls": [
{
"comment_text": "",
"digests": {
"md5": "ae6f8c3015b39e9e7c94d68b14c61715",
"sha256": "9ac51a4d0536ad39f766db6619b80627d71cdbbe4c8a270d62c69f025a005d53"
},
"downloads": -1,
"filename": "blifparser-2.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "ae6f8c3015b39e9e7c94d68b14c61715",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 17368,
"upload_time": "2022-12-12T14:04:31",
"upload_time_iso_8601": "2022-12-12T14:04:31.163426Z",
"url": "https://files.pythonhosted.org/packages/ac/2a/3291f0b3bfd38df5bb91abb9a381e5eb625a476172430d2f2db12bd1f874/blifparser-2.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"md5": "9025d8bdf2c7b2d86f163f7feac0a726",
"sha256": "3e1345a1f04f3b23b66ec1c1121f2728b001c089cde16c45a2b3a2aeaa488c84"
},
"downloads": -1,
"filename": "blifparser-2.0.0.tar.gz",
"has_sig": false,
"md5_digest": "9025d8bdf2c7b2d86f163f7feac0a726",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 17609,
"upload_time": "2022-12-12T14:04:33",
"upload_time_iso_8601": "2022-12-12T14:04:33.188069Z",
"url": "https://files.pythonhosted.org/packages/06/5a/160a94a2c37112326f3ec632c6800deb6ddcca35b231ea7711ccbe253fc3/blifparser-2.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2022-12-12 14:04:33",
"github": true,
"gitlab": false,
"bitbucket": false,
"github_user": "mario33881",
"github_project": "blifparser",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "networkx",
"specs": [
[
"==",
"2.6.3"
]
]
}
],
"lcname": "blifparser"
}