diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index aed93e61a5..92fbb4c6f9 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -19,3 +19,5 @@ - [Linker](./arch/linker.md) - [Validation](./arch/validation.md) - [Codegen](./arch/codegen.md) +- [CFC](./cfc/cfc.md) + - [Model-to-Model Conversion](./cfc/m2m.md) diff --git a/book/src/arch/architecture.md b/book/src/arch/architecture.md index 6a34454e3d..65db19fd61 100644 --- a/book/src/arch/architecture.md +++ b/book/src/arch/architecture.md @@ -2,9 +2,10 @@ ## Overview -RuSTy is a Compiler for Structured Text. -It utilizes the llvm compiler infrastructurue and contributes a [Structured Text](https://en.wikipedia.org/wiki/Structured_text) Frontend that translates Structured Text into llvm's language independent intermediate representation (IR). -The Further optimization and native code generation is performed by the existing LLVM infrastructure, namely llvm's common optimizer and the platform specific backend (see [here](https://www.aosabook.org/en/llvm.html)). +RuSTy is a compiler for IEC61131-3 languages. At the moment, ST and CFC ("FBD") are supported. +It utilizes the LLVM compiler infrastructurue and contributes a [Structured Text](https://en.wikipedia.org/wiki/Structured_text) frontend that translates Structured Text into LLVM's language independent intermediate representation (IR). +[CFC](../cfc/cfc.md) uses a M2M-transformation and reuses most of the ST frontend for compilation. +The further optimization and native code generation is performed by the existing LLVM infrastructure, namely LLVM's common optimizer and the platform specific backend (see [here](https://www.aosabook.org/en/llvm.html)). ```ignore ┌──────────────────┐ ┌───────────────┐ ┌────────────────┐ @@ -21,10 +22,12 @@ This means that this compiler can benefit from llvm's existing compiler-optimiza ## Rusty Frontend Architecture -Ultimately the goal of a compiler frontend, is to translate the original source code into the infrastructure's intermediate representation (in this case we're talking about [LLVM IR](https://llvm.org/docs/LangRef.html)). +Ultimately the goal of a compiler frontend is to translate the original source code into the infrastructure's intermediate representation (in this case we're talking about [LLVM IR](https://llvm.org/docs/LangRef.html)). RuSTy treats this task as a compilation step of its own. While a fully fledged compiler generates machine code as a last step, RuSTy generates LLVM IR assembly code. +## Structured Text + ```ignore ┌────────┐ ┌────────┐ │ Source │ │ LLVM │ @@ -41,3 +44,22 @@ While a fully fledged compiler generates machine code as a last step, RuSTy gene │ │ │ │ │ │ │ │ │ │ └────────────┘ └────────────┘ └────────────┘ └────────────┘ └────────────┘ ``` + +## CFC/FBD + +```ignore + ┌────────┐ ┌────────┐ + │ Source │ │ LLVM │ + │ │ │ IR │ + │ Files │ │ │ + └───┬────┘ └────────┘ + │ ▲ + ▼ │ + ┌────────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌──────┴─────┐ + │ │ │ │ │ │ │ │ │ │ + │ Model-to-Model │ │ │ │ │ │ │ │ │ + │ Transformation ├───►│ Indexer ├──►│ Linker ├──►│ Validation ├──►│ Codegen │ + │ │ │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ │ │ + └────────────────┘ └────────────┘ └────────────┘ └────────────┘ └────────────┘ +``` diff --git a/book/src/cfc.md b/book/src/cfc.md new file mode 100644 index 0000000000..462d73e68b --- /dev/null +++ b/book/src/cfc.md @@ -0,0 +1 @@ +# CFC diff --git a/book/src/cfc/cfc.md b/book/src/cfc/cfc.md new file mode 100644 index 0000000000..6789ab7f65 --- /dev/null +++ b/book/src/cfc/cfc.md @@ -0,0 +1,8 @@ +# CFC (Continous Function Chart) + +RuSTy is compatible with CFC, as per the FBD part detailed in the [IEC61131-3 XML-exchange format](https://www.plcopen.org/system/files/downloads/tc6_xml_v201_technical_doc.pdf). +The CFC implementation borrows extensively from the [ST compiler-pipeline](../arch/architecture.md), with the exception that the lexical analysis and parsing phases are replaced by a model-to-model conversion process. +This involves converting the XML into a structured model, which is then converted into ST AST statements. + + +The next chapter will walk you through the CFC implementation, giving you a better understanding of underlying [code](https://github.com/PLC-lang/rusty/tree/master/compiler/plc_xml). \ No newline at end of file diff --git a/book/src/cfc/m2m.md b/book/src/cfc/m2m.md new file mode 100644 index 0000000000..08e52fd0c5 --- /dev/null +++ b/book/src/cfc/m2m.md @@ -0,0 +1,134 @@ +# Model-to-Model Conversion + +As previously mentioned, the lexical and parsing phases are replaced by a model-to-model conversion process which consists of two steps: +1. Transform the input file (XML) into a data-model +2. Transform the data-model into an AST + +## XML to Data-Model + +Consider the heavily minified CFC file [`MyProgram.cfc`](m2m.md#myprogramcfc), which translates to the CFC chart below. +```ignore + x MyAdd + ┌─────────────┐ ┌─────────────────┐ + │ │ │ exec_id:0 │ + │ ├───────►│ a │ z + │ local_id: 0 │ │ ref_local_id: 0 │ ┌──────────────┐ + └─────────────┘ │ │ │ exec_id: 1 │ + y │ ├─────────►│ │ + ┌─────────────┐ │ │ │ref_local_id:2│ + │ │ │ │ └──────────────┘ + │ ├───────►│ b │ local_id: 3 + │ local_id:1 │ │ ref_local_id: 1 │ + └─────────────┘ └─────────────────┘ + local_id: 2 +``` + +The initial phase of the transformation process involves streaming the entire input file. +During the streaming process, whenever important keywords such as `block` are encountered, they are directly mapped into a corresponding model structure. +For example, when reaching the line `` within the XML file, we generate a model that can be represented as follows: +```rust,ignore +struct Block { + localId: 2, + type_name: "MyAdd", + instance_name: None, + execution_order_id: 0, + variables: [ + InputVariable { ... }, // x, with localId = 0 + InputVariable { ... }, // y, with localId = 1 + OutputVariable { ... }, // MyAdd eventually becoming `z := MyAdd`, with z having a localId = 2 + ] +} +``` + +This process is repeated for every element in the input file which has a corresponding model implementation. For more information on implementation details, see the [model](https://github.com/PLC-lang/rusty/tree/master/compiler/plc_xml/src/model) folder. + +Since the CFC programming language utilizes blocks and their interconnections to establish the program's logic flow, +with the sequencing of block execution and inter-block links represented through corresponding `localId`, `refLocalId` and `excutionOrderId`, +we have to order each element by their execution ID before proceeding to the next phase. +Otherwise the generated AST statements would be out of order and hence semantically incorrect. + +## Data-Model to AST +The final part of the model-to-model transformation takes the input from the previous step and transforms it into an AST which the compiler pipeline understands and can generate code from. +Consider the previous `block` example - the transformer first encounters the element with the `executionOrderId` of 0, which is a call to `myAdd`. +We then check and transform each parameter, input `a` and `b` corresponding to the variables `x` and `y` respectively. The result of this transformation looks as follows: + +```rust,ignore +CallStatement { + operator: myAdd, + parameters: [x, y] +} +``` + + Next, we process the element with an `executionOrderId` of 1, which corresponds to an assignment of the previous call's result to z. This update modifies the generated AST as follows: + +```rust,ignore +AssignmentStatement { + left: z, + right: CallStatement { + operator: myAdd, + parameters: [x, y] + } +} +``` + +While this explanation covers the handling of blocks and variables, there are other elements (e.g. control-flow), that are not discussed here. For more information on implementation details, see [`plc_xml/src/xml_parser`](https://github.com/PLC-lang/rusty/tree/master/compiler/plc_xml/src/xml_parser). + +Finally, after transforming all elements into their respective AST statements, the result is passed to the indexer and subsequently enters the next stages of the compiler pipeline, as described in the [architecture documentation](../arch/architecture.md#rusty-frontend-architecture)). + +## Appendix +### MyAdd.st +```st,ignore +FUNCTION MyAdd : DINT + VAR_INPUT + x, y : DINT; + END_VAR + + MyAdd := x + y; +END_FUNCTION +``` + +### MyProgram.cfc +```xml,ignore + + + PROGRAM myProgram + VAR + x, y, z : DINT; + END_VAR + + + + + x + + + y + + + + + + + + + + + + + + + + + + + + + + + + z + + + + +``` diff --git a/book/src/using_rusty.md b/book/src/using_rusty.md index 4b52a72a6f..4699d1130b 100644 --- a/book/src/using_rusty.md +++ b/book/src/using_rusty.md @@ -2,7 +2,7 @@ > The RuSTy compiler binary is called `plc` -`plc` offers a comprehensive help via the -h (--help) option. +`plc` offers a comprehensive help via the `-h` (`--help`) option. `plc` takes one output-format parameter and any number of input-files. The input files can also be written as [glob patterns](https://en.wikipedia.org/wiki/Glob_(programming)). @@ -16,13 +16,13 @@ the output filename will consist of the first input filename, but with an approp file extension depending on the output file format. A minimal invocation looks like this: -`plc input.st` ... this will take in the file input.st and compile it into a static object that will be written to a file named input.o. +`plc input.st` this will take in the file `input.st` and compile it into a static object that will be written to a file named `input.o`. More examples: - - `plc --ir file1.st file2.st` will compile file1.st and file2.st. -- `plc --ir src/*.st` will compile all st files in the src-folder. -- `plc --ir "**/*.st"` will compile all st-files in the current folder and its subfolders recursively. +- `plc --ir file1.cfc file2.st` will compile file1.cfc and file2.st. +- `plc --ir src/*.st` will compile all ST files in the src-folder. +- `plc --ir "**/*.st"` will compile all ST-files in the current folder and its subfolders recursively. ## Example: Building a hello world program @@ -33,7 +33,7 @@ This example is available under `examples/hello_world.st` in the main RuSTy repo - `main` is our entry point to the program. - To link the program, we are going to use the system's linker using the `--linker=cc` argument. -- On windows, replace this with --linker=clang as cc is usually not available. +- On Windows and MacOS, replace this with `--linker=clang` as cc is usually not available. ```iecst {external} diff --git a/compiler/plc_xml/README.md b/compiler/plc_xml/README.md new file mode 100644 index 0000000000..e89baa6bcc --- /dev/null +++ b/compiler/plc_xml/README.md @@ -0,0 +1,3 @@ +# plc_xml + +This crate contains the CFC implementation of RuSTy, for more information refer to the [book](https://plc-lang.github.io/rusty/cfc/cfc.html). \ No newline at end of file