OMCompiler/Compiler/Template/CodegenMidToC.tpl
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * This file is part of OpenModelica. | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC), | ||
| 5 | * c/o Linköpings universitet, Department of Computer and Information Science, | ||
| 6 | * SE-58183 Linköping, Sweden. | ||
| 7 | * | ||
| 8 | * All rights reserved. | ||
| 9 | * | ||
| 10 | * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR | ||
| 11 | * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8. | ||
| 12 | * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES | ||
| 13 | * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL | ||
| 14 | * VERSION 3, ACCORDING TO RECIPIENTS CHOICE. | ||
| 15 | * | ||
| 16 | * The OpenModelica software and the OSMC (Open Source Modelica Consortium) | ||
| 17 | * Public License (OSMC-PL) are obtained from OSMC, either from the above | ||
| 18 | * address, from the URLs: | ||
| 19 | * http://www.openmodelica.org or | ||
| 20 | * https://github.com/OpenModelica/ or | ||
| 21 | * http://www.ida.liu.se/projects/OpenModelica, | ||
| 22 | * and in the OpenModelica distribution. | ||
| 23 | * | ||
| 24 | * GNU AGPL version 3 is obtained from: | ||
| 25 | * https://www.gnu.org/licenses/licenses.html#GPL | ||
| 26 | * | ||
| 27 | * This program is distributed WITHOUT ANY WARRANTY; without | ||
| 28 | * even the implied warranty of MERCHANTABILITY or FITNESS | ||
| 29 | * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH | ||
| 30 | * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. | ||
| 31 | * | ||
| 32 | * See the full OSMC Public License conditions for more details. | ||
| 33 | * | ||
| 34 | */ | ||
| 35 | |||
| 36 | package CodegenMidToC | ||
| 37 | |||
| 38 | // import CodegenUtil.*; | ||
| 39 | import interface MidCodeTV; | ||
| 40 | import interface SimCodeTV; | ||
| 41 | |||
| 42 | /* | ||
| 43 | maybe do | ||
| 44 | - make a genGoto that generates empty statement if target is next block | ||
| 45 | */ | ||
| 46 | |||
| 47 | ✗ | template genProgram(MidCode.Program p) | |
| 48 | ::= | ||
| 49 | match p | ||
| 50 | case MidCode.PROGRAM(__) then | ||
| 51 | << | ||
| 52 | // number of functions: <% listLength(functions) %> | ||
| 53 | #include "<%name%>.h" | ||
| 54 | #include "util/modelica.h" | ||
| 55 | |||
| 56 | #include "<%name%>_includes.h" | ||
| 57 | |||
| 58 | <% functions |> fn => genFunction(fn) ; separator="\n\n"%> | ||
| 59 | >> | ||
| 60 | end match | ||
| 61 | end genProgram; | ||
| 62 | |||
| 63 | /* | ||
| 64 | template genGlobalDef(Literal lit) | ||
| 65 | ::= | ||
| 66 | match lit | ||
| 67 | case LITSTRING(var=var,value_=value_) then | ||
| 68 | let name = genVarName(var) | ||
| 69 | let dataName = <<_OMC_LIT_DATA_<%name%>>> //<<_OMC_LIT<%name%>_data>> | ||
| 70 | let structName = <<_OMC_LIT_STRUCT_<%name%>>>//<<_OMC_LIT_STRUCT<%name%>>> | ||
| 71 | let escaped = Util.escapeModelicaStringToCString(value_) | ||
| 72 | let escapedLength = System.unescapedStringLength(escaped) // =listLength(value_)? | ||
| 73 | << | ||
| 74 | #define <%dataName%> "<%escaped%>" | ||
| 75 | static const OMC_DEFSTRINGLIT(<%structName%>,<%escapedLength%>,<%dataName%>); | ||
| 76 | #define <%name%> OMC_REFSTRINGLIT(<%structName%>) | ||
| 77 | |||
| 78 | >> | ||
| 79 | case LITRECORD(var=var,args=args) then | ||
| 80 | match var case MidCode.VAR(name=_,ty =ty as DAE.T_METARECORD(__)) then | ||
| 81 | let name = genVarName(var) | ||
| 82 | let dataName = <<_OMC_LIT_DATA_<%name%>>> | ||
| 83 | let structName = <<_OMC_LIT_STRUCT_<%name%>>> | ||
| 84 | << | ||
| 85 | static const OMC_DEFBOXLIT(<%structName%>,<%ty.index%>,<%listLength(args)%>) {<%args |> arg => genVarName(arg) ; separator=","%>}}; | ||
| 86 | #define <%name%> OMC_REFBOXLIT(<%structName%>) | ||
| 87 | |||
| 88 | >> | ||
| 89 | end match | ||
| 90 | else "notimplemented" | ||
| 91 | end match | ||
| 92 | end genGlobalDef; | ||
| 93 | */ | ||
| 94 | |||
| 95 | ✗ | template genFunction(MidCode.Function fn) | |
| 96 | "Generates the body for a Modelica/MetaModelica function." | ||
| 97 | ::= | ||
| 98 | /* | ||
| 99 | The function should accept a thread_data argument. | ||
| 100 | The inputs are normal arguments. | ||
| 101 | The first output is the return value of the function. | ||
| 102 | The rest of the outputs are passed as pointers to the funtion. | ||
| 103 | If there is no output return void? | ||
| 104 | */ | ||
| 105 | match fn | ||
| 106 | case MidCode.FUNCTION(__) then | ||
| 107 | let returnType = if listEmpty(outputs) then "void" else genVarType(listHead(outputs)) | ||
| 108 | |||
| 109 | let arguments = { | ||
| 110 | ("threadData_t *threadData"), | ||
| 111 | (inputs |> i => <<<%genVarType(i)%> <%genVarName(i)%>>> ; separator=", "), | ||
| 112 | (List.restOrEmpty(outputs) |> o => <<<%genVarType(o)%> *outPtr_<%genVarName(o)%>>> ; separator=", ") // TODO: this might not be a great way to pointerify a type | ||
| 113 | } ; separator=",\n " | ||
| 114 | |||
| 115 | << | ||
| 116 | <%returnType%> omc_<%underscorePath(name)%>(<%arguments%>) | ||
| 117 | { | ||
| 118 | <% genLocalDecls(fn, locals, localBufs, localBufPtrs)%> | ||
| 119 | <% genEntry(fn) %> | ||
| 120 | <% genBlocks(fn,body) %> | ||
| 121 | <% genExit(fn) %> | ||
| 122 | } | ||
| 123 | |||
| 124 | <%genInFunction(fn)%> | ||
| 125 | <%genBoxPtrFunction(fn)%> | ||
| 126 | |||
| 127 | >> | ||
| 128 | |||
| 129 | end match | ||
| 130 | end genFunction; | ||
| 131 | |||
| 132 | ✗ | template genInFunction(MidCode.Function fn) | |
| 133 | ::= | ||
| 134 | match fn | ||
| 135 | case MidCode.FUNCTION(__) then | ||
| 136 | let inputDefs = (inputs |> i => <<<%genVarType(i)%> <%genVarName(i)%>;>>; separator="\n") | ||
| 137 | let outputDefs = (outputs |> o => <<<%genVarType(o)%> <%genVarName(o)%>;>>; separator="\n") | ||
| 138 | let inputLines = (inputs |> i => <<if(<%varModelicaRead(i)%>) return 1;>>; separator="\n") | ||
| 139 | let outputLines = (outputs |> o => <<<%varModelicaWrite(o)%>;>>; separator="\n") | ||
| 140 | let callretval = if not listEmpty(outputs) then <<<%genVarName(listHead(outputs))%> = >> | ||
| 141 | let callargs = { | ||
| 142 | ("threadData"), | ||
| 143 | (inputs |> i => <<<%genVarName(i)%>>> ; separator=", "), | ||
| 144 | (List.restOrEmpty(outputs) |> o => <<&<%genVarName(o)%>>> ; separator=", ") | ||
| 145 | } ; separator=",\n " | ||
| 146 | << | ||
| 147 | int in_<%underscorePath(name)%>(threadData_t *threadData, type_description *inArgs, type_description *outVar) | ||
| 148 | { | ||
| 149 | <%inputDefs%> | ||
| 150 | <%outputDefs%> | ||
| 151 | <%inputLines%> | ||
| 152 | OMC_TRY_TOP_INTERNAL() | ||
| 153 | <%callretval%>omc_<%underscorePath(name)%>(<%callargs%>); | ||
| 154 | OMC_CATCH_TOP(return 1) | ||
| 155 | <%outputLines%> | ||
| 156 | <%if listEmpty(outputs) then "write_noretcall(outVar);"%> | ||
| 157 | fflush(NULL); | ||
| 158 | return 0; | ||
| 159 | } | ||
| 160 | >> | ||
| 161 | end match | ||
| 162 | end genInFunction; | ||
| 163 | |||
| 164 | ✗ | template genBoxPtrFunction(MidCode.Function fn) | |
| 165 | ::= | ||
| 166 | match fn | ||
| 167 | case MidCode.FUNCTION(__) then | ||
| 168 | let returnType = if listEmpty(outputs) then "void" else "modelica_metatype" | ||
| 169 | |||
| 170 | let arguments = { | ||
| 171 | ("threadData_t *threadData"), | ||
| 172 | (inputs |> i => <<modelica_metatype <%genVarName(i)%>>> ; separator=", "), | ||
| 173 | (List.restOrEmpty(outputs) |> o => <<modelica_metatype *out_<%genVarName(o)%>>> ; separator=", ") | ||
| 174 | } ; separator=",\n " | ||
| 175 | |||
| 176 | let unboxDefs = ( inputs |> i => | ||
| 177 | if varBoxType(i) then <<<%genVarType(i)%> unbox_<%genVarName(i)%>;>> ; separator="\n") | ||
| 178 | |||
| 179 | let callOutDefs = ( outputs |> o => | ||
| 180 | if varBoxType(o) then <<<%genVarType(o)%> <%genVarName(o)%>;>> ; separator="\n") | ||
| 181 | |||
| 182 | let boxDefs = if not listEmpty(outputs) then <<modelica_metatype out_<%genVarName(listHead(outputs))%>;<%"\n"%>>> | ||
| 183 | |||
| 184 | let unboxes = ( inputs |> i => | ||
| 185 | if varBoxType(i) then <<unbox_<%genVarName(i)%> = <%varUnbox2(i)%>;>> ; separator="\n") | ||
| 186 | |||
| 187 | let callretval = if not listEmpty(outputs) then <<<%if not varBoxType(listHead(outputs)) then "out_"%><%genVarName(listHead(outputs))%> = >> | ||
| 188 | let callvars = { | ||
| 189 | ("threadData"), | ||
| 190 | (inputs |> i => <<<%if varBoxType(i) then "unbox_"%><%genVarName(i)%>>> ; separator=", "), | ||
| 191 | (List.restOrEmpty(outputs) |> o => <<<%if varBoxType(o) then "&" else "out_"%><%genVarName(o)%>>> ; separator=", ") | ||
| 192 | } ; separator=",\n " | ||
| 193 | |||
| 194 | let boxes = { | ||
| 195 | (if not listEmpty(outputs) then (if varBoxType(listHead(outputs)) then <<out_<%genVarName(listHead(outputs))%> = <%varBox(listHead(outputs))%>;>>)), | ||
| 196 | (List.restOrEmpty(outputs) |> o => | ||
| 197 | if varBoxType(o) then <<if(out_<%genVarName(o)%>) *out_<%genVarName(o)%> = <%varBox(o)%>;>> ) | ||
| 198 | } ; separator="\n" | ||
| 199 | |||
| 200 | << | ||
| 201 | #undef boxptr_<%underscorePath(name)%> | ||
| 202 | <%returnType%> boxptr_<%underscorePath(name)%>(<%arguments%>) | ||
| 203 | { | ||
| 204 | <%unboxDefs%> | ||
| 205 | <%callOutDefs%> | ||
| 206 | <%boxDefs%> | ||
| 207 | <%unboxes%> | ||
| 208 | <%callretval%>omc_<%underscorePath(name)%>(<%callvars%>); | ||
| 209 | <%boxes%> | ||
| 210 | <% if listEmpty(outputs) then "return;" else "return out_" + genVarName(listHead(outputs)) + ";" %> | ||
| 211 | } | ||
| 212 | >> | ||
| 213 | end match | ||
| 214 | end genBoxPtrFunction; | ||
| 215 | |||
| 216 | ✗ | template genLocalDecls(MidCode.Function fn, list<MidCode.Var> locals, list<MidCode.VarBuf> localBufs, list<MidCode.VarBufPtr> localBufPtrs) | |
| 217 | ::= | ||
| 218 | << | ||
| 219 | <% locals |> local => genLocalDecl(fn,local) ; separator="\n" %> | ||
| 220 | <% localBufs |> local => genLocalBufDecl(fn,local) ; separator="\n" %> | ||
| 221 | <% localBufPtrs |> local => genLocalBufPtrDecl(fn,local) ; separator="\n" %> | ||
| 222 | >> | ||
| 223 | end genLocalDecls; | ||
| 224 | |||
| 225 | ✗ | template genLocalDecl(MidCode.Function fn, MidCode.Var var) | |
| 226 | ::= | ||
| 227 | << | ||
| 228 | <% match var case MidCode.VAR(volatile=true) then "volatile " end match %><% genVarType(var) %> <% genVarName(var) %>; | ||
| 229 | >> | ||
| 230 | end genLocalDecl; | ||
| 231 | |||
| 232 | ✗ | template genLocalBufDecl(MidCode.Function fn, MidCode.VarBuf var) | |
| 233 | ::= | ||
| 234 | << | ||
| 235 | jmp_buf <% genVarBufName(var) %>; | ||
| 236 | >> | ||
| 237 | end genLocalBufDecl; | ||
| 238 | |||
| 239 | ✗ | template genLocalBufPtrDecl(MidCode.Function fn, MidCode.VarBufPtr var) | |
| 240 | ::= | ||
| 241 | << | ||
| 242 | jmp_buf *<% genVarBufPtrName(var) %>; | ||
| 243 | >> | ||
| 244 | end genLocalBufPtrDecl; | ||
| 245 | |||
| 246 | ✗ | template genEntry(MidCode.Function fn) | |
| 247 | "" | ||
| 248 | ::= | ||
| 249 | match fn | ||
| 250 | case FUNCTION(__) then | ||
| 251 | << | ||
| 252 | goto <% genLabel(entryId) %>; | ||
| 253 | >> | ||
| 254 | end match | ||
| 255 | end genEntry; | ||
| 256 | |||
| 257 | ✗ | template genExit(MidCode.Function fn) | |
| 258 | "" | ||
| 259 | ::= | ||
| 260 | match fn | ||
| 261 | case FUNCTION(__) then | ||
| 262 | let returnString = if listEmpty(outputs) then "" else genVarName(listHead(outputs)) | ||
| 263 | << | ||
| 264 | <% genLabel(exitId) %>: // exit block | ||
| 265 | <% List.restOrEmpty(outputs) |> v => | ||
| 266 | let outPtrName = "outPtr_"+ genVarName(v) | ||
| 267 | << | ||
| 268 | if (<%outPtrName%> != NULL) | ||
| 269 | *<%outPtrName%> = <%genVarName(v)%>; | ||
| 270 | >> ; separator="\n" | ||
| 271 | %> | ||
| 272 | return <%returnString%>; | ||
| 273 | >> | ||
| 274 | end match | ||
| 275 | end genExit; | ||
| 276 | |||
| 277 | ✗ | template genBlocks(MidCode.Function fn, list<MidCode.Block> body) | |
| 278 | "" | ||
| 279 | ::= | ||
| 280 | body |> block => genBlock(fn, block) ; separator="\n" | ||
| 281 | end genBlocks; | ||
| 282 | |||
| 283 | ✗ | template genBlock(MidCode.Function fn, MidCode.Block block) | |
| 284 | "" | ||
| 285 | ::= | ||
| 286 | match block | ||
| 287 | case BLOCK(__) then | ||
| 288 | << | ||
| 289 | <% genLabel(id) %>: | ||
| 290 | <% stmts |> stmt => genStmt(fn, stmt) ; separator="\n" %> | ||
| 291 | <% genTerminator(fn, terminator) %> | ||
| 292 | >> | ||
| 293 | end match | ||
| 294 | end genBlock; | ||
| 295 | |||
| 296 | ✗ | template genLabel(Integer i) | |
| 297 | ::= | ||
| 298 | << | ||
| 299 | label_<% i %> | ||
| 300 | >> | ||
| 301 | end genLabel; | ||
| 302 | |||
| 303 | ✗ | template genVarName(MidCode.Var v) | |
| 304 | ::= | ||
| 305 | match v | ||
| 306 | case MidCode.VAR(__) | ||
| 307 | then name | ||
| 308 | end genVarName; | ||
| 309 | |||
| 310 | ✗ | template genVarBufName(MidCode.VarBuf v) | |
| 311 | ::= | ||
| 312 | match v | ||
| 313 | case MidCode.VARBUF(__) | ||
| 314 | then name | ||
| 315 | end genVarBufName; | ||
| 316 | |||
| 317 | ✗ | template genVarBufPtrName(MidCode.VarBufPtr v) | |
| 318 | ::= | ||
| 319 | match v | ||
| 320 | case MidCode.VARBUFPTR(__) | ||
| 321 | then name | ||
| 322 | end genVarBufPtrName; | ||
| 323 | |||
| 324 | ✗ | template genStmt(MidCode.Function fn, MidCode.Stmt stmt) | |
| 325 | "" | ||
| 326 | ::= | ||
| 327 | match stmt | ||
| 328 | case MidCode.NOP(__) then | ||
| 329 | << | ||
| 330 | ; // NOP | ||
| 331 | >> | ||
| 332 | case MidCode.ASSIGN( | ||
| 333 | dest=MidCode.VAR(name=dest_name,ty=_) | ||
| 334 | ,src=rvalue | ||
| 335 | ) then | ||
| 336 | << | ||
| 337 | <%dest_name%> = <%genRValue(rvalue)%>; | ||
| 338 | >> | ||
| 339 | end match | ||
| 340 | end genStmt; | ||
| 341 | |||
| 342 | ✗ | template genRValue(MidCode.RValue rvalue) | |
| 343 | "" | ||
| 344 | ::= | ||
| 345 | match rvalue | ||
| 346 | case MidCode.VARIABLE(src=src as MidCode.VAR(name=src_name, ty=_)) then | ||
| 347 | << | ||
| 348 | <%src_name%> | ||
| 349 | >> | ||
| 350 | case MidCode.BINARYOP( | ||
| 351 | op=op | ||
| 352 | ,lsrc=lsrc as MidCode.VAR(name=lsrc_name,ty=DAE.T_STRING(__)) | ||
| 353 | ,rsrc=rsrc as MidCode.VAR(name=rsrc_name,ty=DAE.T_STRING(__)) | ||
| 354 | ) then | ||
| 355 | genStringBinaryop(op,lsrc,rsrc) | ||
| 356 | case MidCode.BINARYOP( | ||
| 357 | op=MidCode.POW() | ||
| 358 | ,lsrc=MidCode.VAR(name=lsrc_name, ty=_) | ||
| 359 | ,rsrc=MidCode.VAR(name=rsrc_name, ty=_)) then | ||
| 360 | // TODO: use custom pow for modelica semantics CodegenCFunctions.tpl:4889 | ||
| 361 | << | ||
| 362 | pow(<%lsrc_name%>, <%rsrc_name%>) | ||
| 363 | >> | ||
| 364 | case MidCode.BINARYOP( // c binary ops | ||
| 365 | op=op | ||
| 366 | ,lsrc=MidCode.VAR(name=lsrc_name, ty=_) | ||
| 367 | ,rsrc=MidCode.VAR(name=rsrc_name, ty=_)) then | ||
| 368 | << | ||
| 369 | <%lsrc_name%> <%binaryopToString(op)%> <%rsrc_name%> | ||
| 370 | >> | ||
| 371 | case MidCode.UNARYOP(op=MidCode.BOX(), src=src) then | ||
| 372 | varBox(src) | ||
| 373 | case MidCode.UNARYOP(op=MidCode.UNBOX(), src=src) then | ||
| 374 | varUnbox(src) | ||
| 375 | case MidCode.UNARYOP(op=op, src=src) then | ||
| 376 | << | ||
| 377 | (<%genVarType(src)%>) <%unaryopToString(op)%> <%genVarName(src)%> | ||
| 378 | >> | ||
| 379 | case MidCode.LITERALINTEGER(value=value) then | ||
| 380 | << | ||
| 381 | <%value%> | ||
| 382 | >> | ||
| 383 | case MidCode.LITERALBOOLEAN(value=value) then | ||
| 384 | << | ||
| 385 | <%if value then 1 else 0%> | ||
| 386 | >> | ||
| 387 | case MidCode.LITERALREAL(value=value) then | ||
| 388 | << | ||
| 389 | <%value%> | ||
| 390 | >> | ||
| 391 | case MidCode.LITERALSTRING(value=value) then | ||
| 392 | << | ||
| 393 | mmc_mk_scon("<%Util.escapeModelicaStringToCString(value)%>") | ||
| 394 | >> | ||
| 395 | case MidCode.LITERALMETATYPE(elements=elements,ty=ty) then | ||
| 396 | let metatypeSlots = listLength(elements) | ||
| 397 | let metatypeCtor = genTypeCtorIndex(elements, ty) | ||
| 398 | let elementargs = (elements |> element => <<<%genVarName(element)%>>> ; separator=", ") | ||
| 399 | |||
| 400 | match ty | ||
| 401 | case DAE.T_METARECORD(__) then | ||
| 402 | let arguments = { | ||
| 403 | (<<<%metatypeSlots%>+1>>), | ||
| 404 | (metatypeCtor), | ||
| 405 | (<<&<%genTypeUnderscorePath(ty)%>__desc>>), | ||
| 406 | elementargs | ||
| 407 | } ; separator=", " | ||
| 408 | <<omc_mk_box(<%arguments%>)>> | ||
| 409 | else | ||
| 410 | let arguments = { | ||
| 411 | (<<<%metatypeSlots%>>>), | ||
| 412 | (metatypeCtor), | ||
| 413 | elementargs | ||
| 414 | } ; separator=", " | ||
| 415 | <<omc_mk_box(<%arguments%>)>> | ||
| 416 | |||
| 417 | case MidCode.METAFIELD(src=src, index=index, ty=ty) then | ||
| 418 | <<OMC_BOX_FIELD(<%genVarName(src)%>, <%intAdd(index,1)%>)>> | ||
| 419 | case MidCode.UNIONTYPEVARIANT() then | ||
| 420 | <<(MMC_HDRCTOR(MMC_GETHDR(<%genVarName(src)%>)) - 3)>> | ||
| 421 | case MidCode.ISSOME(src=src) then | ||
| 422 | <<(0==MMC_HDRSLOTS(MMC_GETHDR(<%genVarName(src)%>)) ? 0 : 1)>> | ||
| 423 | case MidCode.ISCONS(src=src) then | ||
| 424 | <<(MMC_GETHDR(<%genVarName(src)%>) == MMC_CONSHDR)>> | ||
| 425 | else "notimplemented" | ||
| 426 | end match | ||
| 427 | end genRValue; | ||
| 428 | |||
| 429 | ✗ | template binaryopToString(MidCode.BinaryOp op) | |
| 430 | ::= | ||
| 431 | match op | ||
| 432 | case MidCode.ADD() then "+" | ||
| 433 | case MidCode.SUB() then "-" | ||
| 434 | case MidCode.MUL() then "*" | ||
| 435 | case MidCode.DIV() then "/" | ||
| 436 | // pow | ||
| 437 | case MidCode.LESS() then "<" | ||
| 438 | case MidCode.LESSEQ() then "<=" | ||
| 439 | case MidCode.GREATER() then ">" | ||
| 440 | case MidCode.GREATEREQ() then ">=" | ||
| 441 | case MidCode.EQUAL() then "==" | ||
| 442 | case MidCode.NEQUAL() then "!=" | ||
| 443 | else "notimplemented" | ||
| 444 | end match | ||
| 445 | end binaryopToString; | ||
| 446 | |||
| 447 | ✗ | template unaryopToString(MidCode.UnaryOp op) | |
| 448 | ::= | ||
| 449 | match op | ||
| 450 | case MidCode.MOVE() then "" | ||
| 451 | case MidCode.UMINUS() then "-" | ||
| 452 | case MidCode.NOT() then "!" | ||
| 453 | else "notimplemented" | ||
| 454 | end match | ||
| 455 | end unaryopToString; | ||
| 456 | |||
| 457 | ✗ | template genStringBinaryop(MidCode.BinaryOp op, MidCode.Var lsrc, MidCode.Var rsrc) | |
| 458 | ::= | ||
| 459 | match op | ||
| 460 | case MidCode.ADD() then | ||
| 461 | << | ||
| 462 | stringAppend(<%genVarName(lsrc)%>, <%genVarName(rsrc)%>) | ||
| 463 | >> | ||
| 464 | else | ||
| 465 | // TODO: | ||
| 466 | // error checking. sub,mul | ||
| 467 | // could optimise equality? CodegenCFunctions.tpl:5163 | ||
| 468 | << | ||
| 469 | 0 <%binaryopToString(op)%> stringCompare(<%genVarName(lsrc)%>, <%genVarName(rsrc)%>) | ||
| 470 | >> | ||
| 471 | end match | ||
| 472 | end genStringBinaryop; | ||
| 473 | |||
| 474 | |||
| 475 | ✗ | template genTerminator(MidCode.Function fn, MidCode.Terminator terminator) | |
| 476 | "" | ||
| 477 | ::= | ||
| 478 | match fn case FUNCTION(locals=_,inputs=_,outputs=_,body=_,entryId=_,exitId=exitId) then | ||
| 479 | // big match expression I guess | ||
| 480 | match terminator | ||
| 481 | case MidCode.RETURN() then | ||
| 482 | << | ||
| 483 | goto <% genLabel(exitId) %>; // exit label | ||
| 484 | >> | ||
| 485 | case MidCode.GOTO(next=label) then | ||
| 486 | << | ||
| 487 | goto <% genLabel(label) %>; | ||
| 488 | >> | ||
| 489 | case MidCode.BRANCH(condition=condition,onTrue=labelTrue, onFalse=labelFalse) then | ||
| 490 | << | ||
| 491 | if (<%genVarName(condition)%>) | ||
| 492 | goto <% genLabel(labelTrue) %>; | ||
| 493 | else | ||
| 494 | goto <% genLabel(labelFalse) %>; | ||
| 495 | >> | ||
| 496 | case MidCode.SWITCH(condition=condition, cases=cases) then | ||
| 497 | << | ||
| 498 | switch (<%genVarName(condition)%>){ | ||
| 499 | <% cases |> (from,to) => | ||
| 500 | << | ||
| 501 | case <%from%>: goto <%genLabel(to)%>; | ||
| 502 | >> | ||
| 503 | ; separator="\n" %> | ||
| 504 | } | ||
| 505 | >> | ||
| 506 | case MidCode.CALL(func=func,builtin=builtin,inputs=inputs,outputs=outputs,next=next) then | ||
| 507 | let returnAssignment = match outputs | ||
| 508 | case {} then "" | ||
| 509 | case MidCode.OUT_WILD() :: _ then "" | ||
| 510 | case MidCode.OUT_VAR(var=var) :: _ then <<<%genVarName(var)%> = >> | ||
| 511 | |||
| 512 | let arguments = { | ||
| 513 | (if not builtin then "threadData"), | ||
| 514 | (inputs |> i => genVarName(i) ; separator=", "), | ||
| 515 | (List.restOrEmpty(outputs) |> o => match o case MidCode.OUT_VAR(var=var) then <<&<%genVarName(var)%>>> else "NULL" ; separator=", ") | ||
| 516 | } ; separator=",\n " | ||
| 517 | |||
| 518 | << | ||
| 519 | <%returnAssignment%><%if not builtin then ("omc_" + underscorePath(func)) else identBuiltinCall(func)%>(<%arguments%>); | ||
| 520 | goto <%genLabel(next)%>; | ||
| 521 | >> | ||
| 522 | /* SimulationRuntime/c/meta/meta_modelica_data.h | ||
| 523 | */ | ||
| 524 | case MidCode.LONGJMP() then | ||
| 525 | // old codegen does fail-goto substitution here | ||
| 526 | // INFO: not allowed to throw to same function | ||
| 527 | << | ||
| 528 | longjmp(*threadData->mmc_jumper,1); | ||
| 529 | >> | ||
| 530 | case MidCode.PUSHJMP(__) then | ||
| 531 | << | ||
| 532 | // PUSHJMP | ||
| 533 | <% genVarBufPtrName(old_buf) %> = threadData->mmc_jumper; | ||
| 534 | threadData->mmc_jumper = &<% genVarBufName(new_buf) %>; | ||
| 535 | setjmp(&<% genVarBufName(new_buf) %>); | ||
| 536 | goto <%genLabel(next)%>; | ||
| 537 | >> | ||
| 538 | case MidCode.POPJMP(__) then | ||
| 539 | << | ||
| 540 | // POPJMP | ||
| 541 | threadData->mmc_jumper = <% genVarBufPtrName(old_buf) %>; | ||
| 542 | goto <%genLabel(next)%>; | ||
| 543 | >> | ||
| 544 | else "notimplemented" | ||
| 545 | end match | ||
| 546 | end genTerminator; | ||
| 547 | |||
| 548 | ✗ | template genVarType(MidCode.Var var) | |
| 549 | "Generate the c type for a variable." | ||
| 550 | ::= | ||
| 551 | match var case VAR(name=_,ty=ty) then | ||
| 552 | match ty | ||
| 553 | case DAE.T_INTEGER(__) | ||
| 554 | case DAE.T_ENUMERATION(__) then | ||
| 555 | "modelica_integer" | ||
| 556 | case DAE.T_BOOL(__) then | ||
| 557 | "modelica_boolean" | ||
| 558 | case DAE.T_REAL(__) then | ||
| 559 | "modelica_real" | ||
| 560 | case DAE.T_STRING(__) then | ||
| 561 | "modelica_string" | ||
| 562 | case DAE.T_METABOXED(__) | ||
| 563 | case DAE.T_METARECORD(__) | ||
| 564 | case DAE.T_METATYPE(__) | ||
| 565 | case DAE.T_METAOPTION(__) | ||
| 566 | case DAE.T_METAARRAY(__) | ||
| 567 | case DAE.T_METATUPLE(__) | ||
| 568 | case DAE.T_METAUNIONTYPE(__) | ||
| 569 | case DAE.T_METALIST(__) then | ||
| 570 | "modelica_metatype" | ||
| 571 | case DAE.T_UNKNOWN() then | ||
| 572 | "unknown" //TODO: fail? | ||
| 573 | case DAE.T_METAPOLYMORPHIC(__) then | ||
| 574 | "error_ metapolymorphic" | ||
| 575 | case DAE.T_METAUNIONTYPE(__) then | ||
| 576 | "error_ metauniontype" | ||
| 577 | case DAE.T_ANYTYPE(__) then | ||
| 578 | "error_anytype" | ||
| 579 | case DAE.T_TUPLE(__) then | ||
| 580 | "error_tuple" | ||
| 581 | else "notimplemented" | ||
| 582 | end match | ||
| 583 | end match | ||
| 584 | end genVarType; | ||
| 585 | |||
| 586 | ✗ | template genTypeCtorIndex(list<MidCode.Var> elements, DAE.Type ty) | |
| 587 | "Generate the c-tag that indicates which record of a uniontype we have." | ||
| 588 | ::= | ||
| 589 | match ty | ||
| 590 | |||
| 591 | case DAE.T_METARECORD(__) then intAdd(index,3) | ||
| 592 | case DAE.T_METAARRAY(__) then 2 | ||
| 593 | case DAE.T_METATUPLE(__) then 0 | ||
| 594 | case DAE.T_METAOPTION(__) then 1 | ||
| 595 | case DAE.T_METALIST(__) then (if listLength(elements) then 1 else 0) | ||
| 596 | else 0 | ||
| 597 | end match | ||
| 598 | end genTypeCtorIndex; | ||
| 599 | |||
| 600 | |||
| 601 | |||
| 602 | ✗ | template genTypeUnderscorePath(DAE.Type ty) | |
| 603 | "generate underscored path from type" | ||
| 604 | ::= | ||
| 605 | // | ||
| 606 | match ty | ||
| 607 | case T_METARECORD(path=path) | ||
| 608 | then underscorePath(path) | ||
| 609 | case T_COMPLEX(complexClassType = RECORD(path = path), varLst = _) | ||
| 610 | then underscorePath(path) | ||
| 611 | else "error: genTypeUnderscorePath" | ||
| 612 | end match | ||
| 613 | end genTypeUnderscorePath; | ||
| 614 | |||
| 615 | ✗ | template varBoxType(MidCode.Var var) | |
| 616 | ::= | ||
| 617 | match var case VAR(name=_,ty=ty) then | ||
| 618 | match ty | ||
| 619 | case T_INTEGER(__) | ||
| 620 | case T_ENUMERATION(__) | ||
| 621 | case T_BOOL(__) | ||
| 622 | case T_REAL(__) then 'modelica_metatype' | ||
| 623 | end match | ||
| 624 | end match | ||
| 625 | end varBoxType; | ||
| 626 | |||
| 627 | ✗ | template varBox(MidCode.Var var) | |
| 628 | ::= | ||
| 629 | match var case VAR(name=name,ty=ty) then | ||
| 630 | match ty | ||
| 631 | case T_INTEGER(__) | ||
| 632 | case T_ENUMERATION(__) then 'omc_mk_icon(<%name%>)' | ||
| 633 | case T_BOOL(__) then 'omc_mk_icon(<%name%>)' | ||
| 634 | case T_REAL(__) then 'omc_mk_rcon(<%name%>)' | ||
| 635 | case T_STRING(__) then 'omc_mk_string(<%name%>)' | ||
| 636 | case T_COMPLEX(__) then 'omc_mk_box(<%name%>)' //? | ||
| 637 | else name | ||
| 638 | end match | ||
| 639 | end match | ||
| 640 | end varBox; | ||
| 641 | |||
| 642 | |||
| 643 | //TODO: split into two functions | ||
| 644 | //non-metaboxed case only necessary for boxptr/in functions | ||
| 645 | //other should be used for normal code | ||
| 646 | ✗ | template varUnbox(MidCode.Var var) | |
| 647 | ::= | ||
| 648 | match var case VAR(name=name,ty=ty) then | ||
| 649 | match ty | ||
| 650 | case T_METABOXED(ty=T_INTEGER(__)) | ||
| 651 | case T_METABOXED(ty=T_ENUMERATION(__))then 'omc_unbox_integer(<%name%>)' | ||
| 652 | case T_METABOXED(ty=T_BOOL(__)) then 'omc_unbox_integer(<%name%>)' | ||
| 653 | case T_METABOXED(ty=T_REAL(__)) then 'omc_unbox_real(<%name%>)' | ||
| 654 | case T_STRING(__) then 'omc_unbox_string(<%name%>)' | ||
| 655 | else name | ||
| 656 | end match | ||
| 657 | end match | ||
| 658 | end varUnbox; | ||
| 659 | |||
| 660 | ✗ | template varUnbox2(MidCode.Var var) | |
| 661 | ::= | ||
| 662 | match var case VAR(name=name,ty=ty) then | ||
| 663 | match ty | ||
| 664 | case T_INTEGER(__) | ||
| 665 | case T_ENUMERATION(__) then 'omc_unbox_integer(<%name%>)' | ||
| 666 | case T_BOOL(__) then 'omc_unbox_integer(<%name%>)' | ||
| 667 | case T_REAL(__) then 'omc_unbox_real(<%name%>)' | ||
| 668 | case T_STRING(__) then 'omc_unbox_string(<%name%>)' | ||
| 669 | else name | ||
| 670 | end match | ||
| 671 | end match | ||
| 672 | end varUnbox2; | ||
| 673 | |||
| 674 | ✗ | template varModelicaRead(MidCode.Var var) | |
| 675 | ::= | ||
| 676 | match var case VAR(name=name,ty=ty) then | ||
| 677 | match ty | ||
| 678 | case T_INTEGER(__) then 'read_modelica_integer(&inArgs, &<%name%>)' | ||
| 679 | case T_BOOL(__) then 'read_modelica_integer(&inArgs, &<%name%>)' | ||
| 680 | case T_REAL(__) then 'read_modelica_real(&inArgs, &<%name%>)' | ||
| 681 | case T_STRING(__) then 'read_modelica_string(&inArgs, &<%name%>)' | ||
| 682 | case T_ENUMERATION(__) then 'read_modelica_integer(&inArgs, &<%name%>)' | ||
| 683 | case T_COMPLEX(__) then 'read_modelica_metatype(&inArgs, &<%name%>)' //? | ||
| 684 | case T_METAUNIONTYPE(__) | ||
| 685 | case T_METALIST(__) | ||
| 686 | case T_METAARRAY(__) | ||
| 687 | case T_METAOPTION(__) | ||
| 688 | case T_METATUPLE(__) then 'read_modelica_metatype(&inArgs, &<%name%>)' | ||
| 689 | end match | ||
| 690 | end match | ||
| 691 | end varModelicaRead; | ||
| 692 | |||
| 693 | ✗ | template varModelicaWrite(MidCode.Var var) | |
| 694 | ::= | ||
| 695 | match var case VAR(name=name,ty=ty) then | ||
| 696 | match ty | ||
| 697 | case T_INTEGER(__) then 'write_modelica_integer(outVar, &<%name%>)' | ||
| 698 | case T_BOOL(__) then 'write_modelica_integer(outVar, &<%name%>)' | ||
| 699 | case T_REAL(__) then 'write_modelica_real(outVar, &<%name%>)' | ||
| 700 | case T_STRING(__) then 'write_modelica_string(outVar, &<%name%>)' | ||
| 701 | case T_ENUMERATION(__) then 'write_modelica_integer(outVar, &<%name%>)' | ||
| 702 | case T_COMPLEX(__) then 'write_modelica_metatype(outVar, &<%name%>)' //? | ||
| 703 | case T_METAUNIONTYPE(__) | ||
| 704 | case T_METALIST(__) | ||
| 705 | case T_METAARRAY(__) | ||
| 706 | case T_METAOPTION(__) | ||
| 707 | case T_METATUPLE(__) then 'write_modelica_metatype(outVar, &<%name%>)' | ||
| 708 | end match | ||
| 709 | end match | ||
| 710 | end varModelicaWrite; | ||
| 711 | |||
| 712 | ✗ | template identName(Absyn.Path path) | |
| 713 | ::= | ||
| 714 | match path | ||
| 715 | case Absyn.IDENT(__) then name | ||
| 716 | end identName; | ||
| 717 | |||
| 718 | ✗ | template identBuiltinCall(Absyn.Path path) | |
| 719 | ::= | ||
| 720 | match path | ||
| 721 | case Absyn.IDENT(name="clock") then "mmc_clock" | ||
| 722 | case Absyn.IDENT(name="anyString") then "mmc_anyString" | ||
| 723 | case Absyn.IDENT(name="fail") then "MMC_THROW_INTERNAL" | ||
| 724 | case Absyn.IDENT(name="intMod") then "modelica_mod_integer" | ||
| 725 | //TODO: print -> puts(omc_string_data(...)) | ||
| 726 | //TODO: mmc_get_field (usual macro solution) | ||
| 727 | //TODO: bitwise operators (could be done in DAEToMid instead) | ||
| 728 | //TODO: mod, div, max, min? | ||
| 729 | //needs some more advanced expression generation with arguments as input | ||
| 730 | |||
| 731 | case Absyn.IDENT(__) then name | ||
| 732 | |||
| 733 | end identBuiltinCall; | ||
| 734 | |||
| 735 | |||
| 736 | |||
| 737 | /* | ||
| 738 | ++++++++++++++++++++++++++++++++++++++++ | ||
| 739 | Copied from | ||
| 740 | CodegenUtil.tpl | ||
| 741 | |||
| 742 | Don't know how to import across directories. | ||
| 743 | */ | ||
| 744 | |||
| 745 | ✗ | template replaceDotAndUnderscore(String str) | |
| 746 | "Replace _ with __ and dot in identifiers with _" | ||
| 747 | ::= | ||
| 748 | match str | ||
| 749 | case name then | ||
| 750 | let str_dots = System.stringReplace(name,".", "_") | ||
| 751 | let str_underscores = System.stringReplace(str_dots, "_", "__") | ||
| 752 | System.unquoteIdentifier(str_underscores) | ||
| 753 | end replaceDotAndUnderscore; | ||
| 754 | |||
| 755 | |||
| 756 | ✗ | template underscorePath(Absyn.Path path) | |
| 757 | "Generate paths with components separated by underscores. | ||
| 758 | Replaces also the . in identifiers with _. | ||
| 759 | The dot might happen for world.gravityAccleration" | ||
| 760 | ::= | ||
| 761 | match path | ||
| 762 | case Absyn.QUALIFIED(__) then | ||
| 763 | '<%replaceDotAndUnderscore(name)%>_<%underscorePath(path)%>' | ||
| 764 | case Absyn.IDENT(__) then | ||
| 765 | replaceDotAndUnderscore(name) | ||
| 766 | case Absyn.FULLYQUALIFIED(__) then | ||
| 767 | underscorePath(path) | ||
| 768 | end underscorePath; | ||
| 769 | |||
| 770 | |||
| 771 | //++++++++++++++++++++++++++++++++++++++++ | ||
| 772 | |||
| 773 | annotation(__OpenModelica_Interface="codegen"); | ||
| 774 | end CodegenMidToC; | ||
| 775 |