123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420 |
- import { BaseConverter } from "./../baseConverter";
- import {
- Declaration,
- ArrayDeclaration,
- FunctionCall
- } from "../../ast/commands";
- import { Types } from "../../typeSystem/types";
- import { ArrayType } from "../../typeSystem/array_type";
- import {
- InfixApp,
- StringLiteral,
- VariableLiteral,
- UnaryApp,
- BoolLiteral
- } from "../../ast/expressions";
- import { TextNode } from "./ast/textNode";
- import { Pointer } from "./types/pointer";
- import { Operators } from "../../ast/operators";
- import { LocalizedStrings } from "./../../services/localizedStringsService";
- import { LanguageDefinedFunction } from "../../processor/definedFunctions";
- const FORBIDDEN_FUNCS = [
- "$isReal",
- "$isInt",
- "$isBool",
- "$castReal",
- "$castInt",
- "$castBool",
- "$castString",
- "$max",
- "$min",
- "$invert"
- ];
- export class CConverter extends BaseConverter {
- constructor (ivprogAST) {
- super(ivprogAST);
- this.globalVars = [];
- this.cAST = {
- includes: new Set(),
- globalVars: [],
- functionDecl: [],
- functions: []
- };
- this.currentVars = [];
- this.currentCommands = [];
- this.auxCounter = 1;
- }
- createAuxID () {
- let id = null;
- let symbol = true;
- while (symbol) {
- id = `aux_${this.auxCounter}`;
- this.auxCounter += 1;
- symbol = this.findSymbol(id);
- }
- return id;
- }
- resetContext () {
- this.currentVars = [];
- this.currentCommands = [];
- }
- toText () {
- this.doConvertion();
- }
- doConversion () {
- this.ivprogAST.global.forEach(decl => {
- if (decl instanceof ArrayDeclaration) {
- if (Types.STRING.isCompatible(decl.type.innerType)) {
- throw new Error(
- "Cannot convert a program that contains an array of text"
- );
- }
- }
- this.insertGlobalSymbol(decl.id, decl);
- if (decl instanceof ArrayDeclaration) {
- let initial = decl.initial;
- if (initial) {
- initial = this.convertArrayInit(initial);
- }
- const lines = this.convertExpression(decl.lines);
- if (decl.isVector) {
- this.cAST.globalVars.push(
- new ArrayDeclaration(
- decl.id,
- decl.type,
- lines,
- null,
- initial,
- decl.isConst
- )
- );
- } else {
- const columns = this.convertExpression(decl.lines);
- this.cAST.globalVars.push(
- new ArrayDeclaration(
- decl.id,
- decl.type,
- lines,
- columns,
- initial,
- decl.isConst
- )
- );
- }
- } else {
- if (decl.type.isCompatible(Types.STRING)) {
- if (
- decl.initial == null ||
- !(decl.initial instanceof StringLiteral)
- ) {
- throw new Error(
- "String must have a literal as its initial value to be converted to C"
- );
- }
- }
- let initial = decl.initial;
- if (initial) {
- initial = this.convertExpression(initial);
- }
- if (decl.type.isCompatible(Types.STRING)) {
- // Must be a pointer since concatenation under the same symbol is expected (str = str + "abc")
- this.cAST.globalVars.push(
- new Declaration(
- decl.id,
- new Pointer(decl.type),
- initial,
- decl.isConst
- )
- );
- } else {
- this.cAST.globalVars.push(
- new Declaration(decl.id, decl.type, initial, decl.isConst)
- );
- }
- }
- });
- // convert every function...
- for (let i = 0; i < this.ivprogAST.functions.length; i += 1) {
- const func = this.ivprogAST.functions[i];
- if (func.isMain) {
- // deal with main function
- } else {
- // TODO
- }
- }
- }
- convertExpression (expression) {
- const type = this.evaluateExpressionType(expression);
- if (type instanceof ArrayType) {
- // TODO
- } else if (Types.STRING.isCompatible(type)) {
- return this.convertStringExpression(expression);
- } else if (Types.BOOLEAN.isCompatible(type)) {
- return this.convertBooleanExpression(expression);
- } else {
- // It's a numeric expression
- return this.convertNumericExpression(expression);
- }
- }
- convertArrayInit (decl) {
- return null;
- }
- convertNumericExpression (expression) {
- if (expression instanceof UnaryApp) {
- const leftExp = this.convertNumericExpression(expression.left);
- return new TextNode(`${expression.op.value}${leftExp.toString()}`);
- } else if (expression instanceof InfixApp) {
- const leftExp = this.convertNumericExpression(expression.left);
- const rightExp = this.convertNumericExpression(expression.right);
- return new TextNode(
- `${leftExp.toString()} ${expression.op.value} ${rightExp.toString()}`
- );
- } else if (expression instanceof FunctionCall) {
- let funcName = expression.id;
- const langFun = LanguageDefinedFunction.getFunction(funcName);
- if (langFun) {
- this.isValidFunction(funcName);
- // function is valid, do we need to import any c lib?
- // tan, cos, sen, sqrt, pow ...
- const funcInfo = this.convertFunctionCall(funcName);
- this.cAST.includes.add(funcInfo.lib);
- funcName = funcInfo.name;
- }
- // need to verify every parameter...
- const paramList = [];
- for (let i = 0; i < expression.parametersSize; i += 1) {
- const param = expression.actualParameters[i];
- const paramExp = this.convertExpression(param);
- paramList.push(paramExp.toString());
- }
- const paramString = paramList.join(", ");
- return TextNode(`${funcName}(${paramString})`);
- } else {
- return expression;
- }
- }
- convertBooleanExpression (expression) {
- if (expression instanceof UnaryApp) {
- const left = this.convertExpression(expression.left);
- return new TextNode(`!${left.toString()}`);
- } else if (expression instanceof InfixApp) {
- const leftExp = this.convertExpression(expression.left);
- const rightExp = this.convertExpression(expression.right);
- const op = expression.op;
- switch (op.ord) {
- case Operators.AND.ord:
- return new TextNode(
- `${leftExp.toString()} && ${rightExp.toString()}`
- );
- case Operators.OR.ord:
- return new TextNode(
- `${leftExp.toString()} || ${rightExp.toString()}`
- );
- default:
- return new TextNode(
- `${leftExp.toString()} ${op.value} ${rightExp.toString()}`
- );
- }
- } else if (expression instanceof BoolLiteral) {
- this.cAST.includes.add("stdbool.h");
- const value = expression.value ? "true" : "false";
- return new TextNode(value);
- } else if (expression instanceof FunctionCall) {
- // Function call... if it's one of the convert/check functions DO NOT convert the code
- let funcName = expression.id;
- const langFun = LanguageDefinedFunction.getFunction(funcName);
- if (langFun) {
- this.isValidFunction(funcName);
- const funcInfo = this.convertFunctionCall(funcName);
- this.cAST.includes.add(funcInfo.lib);
- funcName = funcInfo.name;
- }
- const paramList = [];
- for (let i = 0; i < expression.parametersSize; i += 1) {
- const param = expression.actualParameters[i];
- const paramExp = this.convertExpression(param);
- paramList.push(paramExp.toString());
- }
- const paramString = paramList.join(", ");
- return TextNode(`${funcName}(${paramString})`);
- } else {
- return expression;
- }
- }
- convertStringExpression (expression) {
- if (expression instanceof InfixApp) {
- const leftType = this.evaluateExpressionType(expression.left);
- const rightType = this.evaluateExpressionType(expression.right);
- if (
- leftType.isCompatible(Types.STRING) &&
- rightType.isCompatible(Types.STRING)
- ) {
- // BOTH strings....
- // create a temp var with size equals to left + right + 1
- const leftExp = this.convertStringExpression(expression.left);
- const rightExp = this.convertStringExpression(expression.right);
- this.currentCommands.push({
- value:
- "As 3 linhas seguintes convertem a expressão " +
- expression.toString()
- });
- const auxID = this.createAuxID();
- this.createCharPointer(auxID, true, leftExp, rightExp);
- this.createCharCopy(auxID, leftExp);
- this.createCharConcat(auxID, rightExp);
- return new VariableLiteral(auxID);
- } else if (leftType.isCompatible(Types.STRING)) {
- // left is a string, right needs conversion
- const leftExp = this.convertStringExpression(expression.left);
- const rightExp = this.convertExpression(expression.right);
- const formatString = this.getFormatStringFromType(rightType);
- const auxConvert = this.createAuxID();
- this.convertToString(auxConvert, formatString, rightExp);
- const auxID = this.createAuxID();
- this.createCharPointer(auxID, true, leftExp, auxConvert);
- this.createCharCopy(auxID, leftExp);
- this.createCharConcat(auxID, auxConvert);
- return new VariableLiteral(auxID);
- } else {
- // right is a string, left needs conversion
- const leftExp = this.convertExpression(expression.left);
- const rightExp = this.convertStringExpression(expression.right);
- const formatString = this.getFormatStringFromType(leftType);
- const auxConvert = this.createAuxID();
- this.convertToString(auxConvert, formatString, leftExp);
- const auxID = this.createAuxID();
- this.createCharPointer(auxID, true, auxConvert, rightExp);
- this.createCharCopy(auxID, auxConvert);
- this.createCharConcat(auxID, rightExp);
- return new VariableLiteral(auxID);
- }
- } else if (expression instanceof StringLiteral) {
- return expression;
- } else if (expression instanceof FunctionCall) {
- let funcName = expression.id;
- const langFun = LanguageDefinedFunction.getFunction(funcName);
- if (langFun) {
- this.isValidFunction(funcName);
- const funcInfo = this.convertFunctionCall(funcName);
- this.cAST.includes.add(funcInfo.lib);
- funcName = funcInfo.name;
- }
- const paramList = [];
- for (let i = 0; i < expression.parametersSize; i += 1) {
- const param = expression.actualParameters[i];
- const paramExp = this.convertExpression(param);
- paramList.push(paramExp.toString());
- }
- const paramString = paramList.join(", ");
- return TextNode(`${funcName}(${paramString})`);
- } else {
- return expression;
- }
- }
- getFormatStringFromType (type) {
- switch (type.ord) {
- case Types.INTEGER.ord:
- case Types.BOOLEAN.ord:
- return "%d";
- case Types.STRING.ord:
- return "%s";
- default:
- return "%g";
- }
- }
- convertToString (id, format, expression) {
- this.currentCommands.push({
- value:
- "As 3 linhas seguintes convertem a expressão " + expression.toString()
- });
- const lenID = this.createAuxID();
- this.currentCommands.push(
- new TextNode(
- `int ${lenID} = snprintf(NULL, 0, ${format}, ${expression.toString()})`
- )
- );
- this.createCharPointer(id, true, lenID);
- this.currentCommands.push(
- new TextNode(
- `snprintf(${id}, ${lenID} + 1, ${format}, ${expression.toString()})`
- )
- );
- }
- createCharPointer (id, plusOne, ...args) {
- this.cAST.includes.add("stdlib.h");
- const funArgs = [];
- for (let i = 0; i < args.length; i += 1) {
- funArgs.push(`sizeof(${args[i].toString()})`);
- }
- if (plusOne) {
- funArgs.push("1");
- }
- const params = funArgs.join(" + ");
- const initial = new TextNode(`malloc(${params})`);
- const decl = new Declaration(id, new Pointer(Types.STRING), initial);
- this.currentCommands.push(decl);
- }
- createCharCopy (id, arg) {
- this.cAST.includes.add("string.h");
- const cmd = new TextNode(`strcpy(${id}, ${arg.toString()})`);
- this.currentCommands.push(cmd);
- }
- createCharConcat (id, arg) {
- this.cAST.includes.add("string.h");
- const cmd = new TextNode(`strcat(${id}, ${arg.toString()})`);
- this.currentCommands.push(cmd);
- }
- convertFunctionCall (name) {
- let id = name;
- if (name.indexOf(".") !== -1) {
- const names = name.split(".");
- id = names[1];
- }
- switch (id) {
- case "$log":
- return { lib: "math.h", name: "log10" };
- case "$sin":
- case "$cos":
- case "$tan":
- case "$sqrt":
- case "$pow":
- return { lib: "math.h", name: id.substring(1) };
- case "$rand":
- return { lib: "stdlib.h", name: id.substring(1) };
- case "$abs":
- return { lib: "stdlib.h", name: id.substring(1) };
- }
- }
- isValidFunction (id) {
- for (const name in FORBIDDEN_FUNCS) {
- if (id.indexOf(name) !== -1) {
- throw new Error(
- `Não é possível converter um código que faz uso da função ${LocalizedStrings.translateInternalFunction(
- name
- )}.`
- );
- }
- }
- }
- }
|