etisserant@0: /*
msousa@261: * matiec - a compiler for the programming languages defined in IEC 61131-3
msousa@261: * Copyright (C) 2003-2011 Mario de Sousa (msousa@fe.up.pt)
Edouard@279: * Copyright (C) 2007-2011 Laurent Bessard and Edouard Tisserant
msousa@261: *
msousa@261: * This program is free software: you can redistribute it and/or modify
msousa@261: * it under the terms of the GNU General Public License as published by
msousa@261: * the Free Software Foundation, either version 3 of the License, or
msousa@261: * (at your option) any later version.
msousa@261: *
msousa@261: * This program is distributed in the hope that it will be useful,
msousa@261: * but WITHOUT ANY WARRANTY; without even the implied warranty of
msousa@261: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
msousa@261: * GNU General Public License for more details.
msousa@261: *
msousa@261: * You should have received a copy of the GNU General Public License
msousa@261: * along with this program. If not, see .
msousa@261: *
etisserant@0: *
etisserant@0: * This code is made available on the understanding that it will not be
etisserant@0: * used in safety-critical situations without a full and competent review.
etisserant@0: */
etisserant@0:
etisserant@0: /*
msousa@261: * An IEC 61131-3 compiler.
etisserant@0: *
etisserant@0: * Based on the
etisserant@0: * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
etisserant@0: *
etisserant@0: */
etisserant@0:
etisserant@0: /*
etisserant@0: ****************************************************************
etisserant@0: ****************************************************************
etisserant@0: ****************************************************************
etisserant@0: ********* *********
etisserant@0: ********* *********
etisserant@0: ********* O V E R A L L A R C H I T E C T U R E *********
etisserant@0: ********* *********
etisserant@0: ********* *********
etisserant@0: ****************************************************************
etisserant@0: ****************************************************************
etisserant@0: ****************************************************************
etisserant@0:
etisserant@0: The compiler works in 4(+1) stages:
etisserant@0: Stage 1 - Lexical analyser - implemented with flex (iec.flex)
etisserant@0: Stage 2 - Syntax parser - implemented with bison (iec.y)
etisserant@0: Stage 3 - Semantics analyser - not yet implemented
etisserant@0: Stage 4 - Code generator - implemented in C++
etisserant@0: Stage 4+1 - Binary code generator - gcc, javac, etc...
etisserant@0:
etisserant@0:
etisserant@0: Data structures passed between stages, in global variables:
etisserant@0: 1->2 : tokens (int), and token values (char *)
etisserant@0: 2->1 : symbol tables (defined in symtable.hh)
etisserant@0: 2->3 : abstract syntax tree (tree of C++ classes, in absyntax.hh file)
etisserant@0: 3->4 : Same as 2->3
etisserant@0: 4->4+1 : file with program in c, java, etc...
etisserant@0:
etisserant@0:
etisserant@0: The compiler works in several passes:
etisserant@0: Pass 1: executes stages 1 and 2 simultaneously
etisserant@0: Pass 2: executes stage 3
etisserant@0: Pass 3: executes stage 4
etisserant@0: Pass 4: executes stage 4+1
etisserant@0: */
etisserant@0:
etisserant@0:
etisserant@0:
conti@746: #include
greg@186: #include
etisserant@139: #include
conti@746: #include
conti@746: #include
conti@746: #include
conti@746:
conti@746:
conti@746: #include "config/config.h"
conti@746: #include "absyntax/absyntax.hh"
conti@746: #include "absyntax_utils/absyntax_utils.hh"
conti@746: #include "stage1_2/stage1_2.hh"
conti@746: #include "stage3/stage3.hh"
conti@746: #include "stage4/stage4.hh"
conti@746: #include "main.hh"
conti@746:
msousa@350:
conti@374: #ifndef HGVERSION
conti@746: #define HGVERSION ""
conti@374: #endif
msousa@350:
conti@746:
msousa@596:
msousa@596: void error_exit(const char *file_name, int line_no, const char *errmsg, ...) {
msousa@596: va_list argptr;
msousa@596: va_start(argptr, errmsg); /* second argument is last fixed pamater of error_exit() */
msousa@596:
msousa@596: fprintf(stderr, "\nInternal compiler error in file %s at line %d", file_name, line_no);
msousa@596: if (errmsg != NULL) {
msousa@596: fprintf(stderr, ": ");
msousa@596: vfprintf(stderr, errmsg, argptr);
msousa@596: } else {
msousa@596: fprintf(stderr, ".");
msousa@596: }
msousa@596: fprintf(stderr, "\n");
msousa@596: va_end(argptr);
msousa@596:
etisserant@0: exit(EXIT_FAILURE);
etisserant@0: }
etisserant@0:
etisserant@0:
etisserant@0: static void printusage(const char *cmd) {
mjsousa@878: printf("\nsyntax: %s [] [-O ] [-I ] [-T ] \n", cmd);
mjsousa@878: printf(" -h : show this help message\n");
mjsousa@878: printf(" -v : print version number\n");
mjsousa@878: printf(" -f : display full token location on error messages\n");
mjsousa@956: printf(" -p : allow use of forward references (a non-standard extension?)\n");
mjsousa@946: printf(" -l : use a relaxed datatype equivalence model (a non-standard extension?)\n");
mjsousa@946: printf(" -s : allow use of safe datatypes (SAFEBOOL, etc.) (defined in PLCOpen Safety)\n"); // PLCopen TC5 "Safety Software Technical Specification - Part 1" v1.0
mjsousa@933: printf(" -r : allow use of references (REF_TO, REF, ^, NULL) (an IEC 61131-3 v3 feature)\n");
mjsousa@932: printf(" -R : allow use of REF_TO ANY datatypes (a non-standard extension!)\n");
mjsousa@932: printf(" as well as REF_TO in ARRAYs and STRUCTs (a non-standard extension!)\n");
mjsousa@980: printf(" -a : allow use of non-literals in array size limits (a non-standard extension!)\n");
mjsousa@878: printf(" -c : create conversion functions for enumerated data types\n");
mjsousa@878: printf(" -O : options for output (code generation) stage. Available options for %s are...\n", cmd);
mjsousa@878: stage4_print_options();
msousa@261: printf("\n");
mjsousa@873: printf("%s - Copyright (C) 2003-2014 \n"
msousa@261: "This program comes with ABSOLUTELY NO WARRANTY!\n"
msousa@362: "This is free software licensed under GPL v3, and you are welcome to redistribute it under the conditions specified by this license.\n", PACKAGE_NAME);
etisserant@0: }
etisserant@0:
etisserant@0:
mjsousa@946: /* declare the global options variable */
mjsousa@946: runtime_options_t runtime_options;
mjsousa@946:
etisserant@0:
etisserant@0: int main(int argc, char **argv) {
mjsousa@959: symbol_c *tree_root, *ordered_tree_root;
lbessard@46: char * builddir = NULL;
mario@177: int optres, errflg = 0;
conti@521: int path_len;
conti@746:
mjsousa@867: /* Default values for the command line options... */
mjsousa@956: runtime_options.pre_parsing = false; /* allow use of forward references (run pre-parsing phase before the definitive parsing phase that builds the AST) */
mjsousa@946: runtime_options.safe_extensions = false; /* allow use of SAFExxx datatypes */
mjsousa@946: runtime_options.full_token_loc = false; /* error messages specify full token location */
mjsousa@946: runtime_options.conversion_functions = false; /* Create a conversion function for derived datatype */
mjsousa@946: runtime_options.nested_comments = false; /* Allow the use of nested comments. */
mjsousa@946: runtime_options.ref_standard_extensions = false; /* Allow the use of REFerences (keywords REF_TO, REF, DREF, ^, NULL). */
mjsousa@946: runtime_options.ref_nonstand_extensions = false; /* Allow the use of non-standard extensions to REF_TO datatypes: REF_TO ANY, and REF_TO in struct elements! */
mjsousa@980: runtime_options.nonliteral_in_array_size= false; /* Allow the use of constant non-literals when specifying size of arrays (ARRAY [1..max] OF INT) */
mjsousa@946: runtime_options.includedir = NULL; /* Include directory, where included files will be searched for... */
mjsousa@946:
mjsousa@946: /* Default values for the command line options... */
mjsousa@946: runtime_options.relaxed_datatype_model = false; /* by default use the strict datatype equivalence model */
mjsousa@946:
mario@181: /******************************************/
mario@181: /* Parse command line options... */
mario@181: /******************************************/
mjsousa@980: while ((optres = getopt(argc, argv, ":nhvfplsrRacI:T:O:")) != -1) {
mario@177: switch(optres) {
mario@177: case 'h':
mario@177: printusage(argv[0]);
mario@177: return 0;
msousa@362: case 'v':
mjsousa@878: fprintf(stdout, "%s version %s\n" "changeset id: %s\n", PACKAGE_NAME, PACKAGE_VERSION, HGVERSION);
conti@746: return 0;
mjsousa@980: case 'l': runtime_options.relaxed_datatype_model = true; break;
mjsousa@980: case 'p': runtime_options.pre_parsing = true; break;
mjsousa@980: case 'f': runtime_options.full_token_loc = true; break;
mjsousa@980: case 's': runtime_options.safe_extensions = true; break;
mjsousa@980: case 'R': runtime_options.ref_standard_extensions = true; /* use of REF_TO ANY implies activating support for REF extensions! */
mjsousa@980: runtime_options.ref_nonstand_extensions = true; break;
mjsousa@980: case 'r': runtime_options.ref_standard_extensions = true; break;
mjsousa@980: case 'a': runtime_options.nonliteral_in_array_size = true; break;
mjsousa@980: case 'c': runtime_options.conversion_functions = true; break;
mjsousa@980: case 'n': runtime_options.nested_comments = true; break;
mario@177: case 'I':
conti@521: /* NOTE: To improve the usability under windows:
conti@521: * We delete last char's path if it ends with "\".
conti@521: * In this way compiler front-end accepts paths with or without
conti@521: * slash terminator.
conti@521: */
conti@521: path_len = strlen(optarg) - 1;
conti@521: if (optarg[path_len] == '\\') optarg[path_len]= '\0';
mjsousa@946: runtime_options.includedir = optarg;
mario@177: break;
lbessard@179: case 'T':
conti@521: /* NOTE: see note above */
conti@521: path_len = strlen(optarg) - 1;
conti@521: if (optarg[path_len] == '\\') optarg[path_len]= '\0';
lbessard@179: builddir = optarg;
lbessard@179: break;
mjsousa@878: case 'O':
mjsousa@878: if (stage4_parse_options(optarg) < 0) errflg++;
mjsousa@878: break;
mjsousa@878: case ':': /* -I, -T, or -O without operand */
mario@177: fprintf(stderr, "Option -%c requires an operand\n", optopt);
mario@177: errflg++;
mario@177: break;
mario@177: case '?':
mario@181: fprintf(stderr, "Unrecognized option: -%c\n", optopt);
mario@181: errflg++;
mario@181: break;
mario@177: default:
mario@181: fprintf(stderr, "Unknown error while parsing command line options.");
mario@177: errflg++;
mario@177: break;
mario@177: }
etisserant@0: }
etisserant@0:
mario@177: if (optind == argc) {
mario@177: fprintf(stderr, "Missing input file\n");
mario@177: errflg++;
lbessard@136: }
lbessard@136:
mario@177: if (optind > argc) {
mario@177: fprintf(stderr, "Too many input files\n");
mario@177: errflg++;
mario@177: }
mario@177:
mario@177: if (errflg) {
conti@746: printusage(argv[0]);
conti@746: return EXIT_FAILURE;
lbessard@136: }
lbessard@136:
lbessard@136:
mario@181: /***************************/
mario@181: /* Run the compiler... */
mario@181: /***************************/
etisserant@0: /* 1st Pass */
mjsousa@946: if (stage1_2(argv[optind], &tree_root) < 0)
etisserant@0: return EXIT_FAILURE;
etisserant@0:
etisserant@0: /* 2nd Pass */
msousa@315: /* basically loads some symbol tables to speed up look ups later on */
msousa@315: absyntax_utils_init(tree_root);
msousa@315: /* moved to bison, although it could perfectly well still be here instead of in bison code. */
msousa@315: //add_en_eno_param_decl_c::add_to(tree_root);
msousa@315:
mjsousa@946: /* Do semantic verification of code */
mjsousa@959: if (stage3(tree_root, &ordered_tree_root) < 0)
etisserant@0: return EXIT_FAILURE;
ccb@202:
etisserant@0: /* 3rd Pass */
mjsousa@959: if (stage4(ordered_tree_root, builddir) < 0)
etisserant@0: return EXIT_FAILURE;
etisserant@0:
etisserant@0: /* 4th Pass */
msousa@315: /* Call gcc, g++, or whatever... */
etisserant@0: /* Currently implemented in the Makefile! */
etisserant@0:
etisserant@0: return 0;
etisserant@0: }
etisserant@0:
etisserant@0: