|Introdução ao Desenvolvimento de Compiladores|
|Aspectos Teóricos de Análise Lexical|
|A Ferramenta Flex|
|Introdução à Sintaxe|
|Análise Sintáctica Descendente|
|A Ferramenta YACC|
|Análise Sintáctica Ascendente|
|Geração de Código|
|Tópicos de Optimização|
Our compiler development approach adopts the classical structure, beginning with lexical analysis and moving through syntactic analysis, semantic analysis, and finally code generation. This process utilizes two code generators -- one for creating the scanner and another for developing the syntactic parser -- and leverages modules manually crafted by the programmer.
While we adhere to the traditional versions of the scanner and parser generators (Flex and BYACC), we transition from C to C++. Our usage of C++ extends beyond merely swapping languages and scripting several classes. Instead, we exploit the full potential of object-oriented programming (OOP) and design patterns, leading to a compiler that is organized in a logical, user-friendly manner, and is amenable to modifications. These features are paramount in terms of programming effort and pedagogical objectives.
Employing C++ not only upgrades the quality of C but also allows the native application of OOP architecture principles. Though these principles could be implemented in C, it would entail increased development complexities. Thus, our interest isn't confined to recompiling old C code with a C++ compiler and leaving the outcome to fate. Instead, the incorporation of C++ is designed to impact every facet of compiler development, ranging from the comprehensive organization of the compiler to the composition of each component.
The decision to use C++ isn't solely about selecting a programming language; it's also about determining the authorship of the compiler code. If for a human programmer, using C++ is merely a competence issue, tools that generate part of the compiler's code need meticulous selection to ensure the produced code operates as anticipated.
Several widely-used compiler development support tools, such as the Flex lexical analyzer and the Bison parser generator, natively support C++. Conversely, some tools, like Berkeley YACC (BYACC), only support C. In the former scenario, the generated code and the objects it aids merely need integration into the architecture. In the latter scenario, additional adaptations might be necessary, performed either by the programmer or via specialized wrappers. Despite being C code, BYACC-generated parsers, as we will see, are relatively straightforward to adapt to C++.
Transitioning from fundamental OOP principles to the realm of design patterns may seem like a small leap, but it brings substantial advantages. Effective use of select design patterns -- particularly, but not limited to, the Composite and Visitor design patterns -- results in a more robust compiler and a streamlined development process.