Skip to content

Commit 99fbaa6

Browse files
committed
Improve codegens for arrays
1 parent 7bb1d91 commit 99fbaa6

18 files changed

+835
-262
lines changed

editor/src/main/scala/dev/sacode/flowrun/FlowRunEditor.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class FlowRunEditor(
107107
// meaning not-changeable with checkboxes
108108
private val fixedLayout = flowRunElements.mountElem.classList.exists(_.startsWith("flowrun-layout"))
109109

110-
if fixedLayout then
110+
if fixedLayout then
111111
flowRunElements.configWidget.querySelector(".flowrun-config-layout").remove()
112112
flowRunElements.showConfigButton.remove()
113113
else updateLayout()

interpreter/shared/src/main/scala/dev/sacode/flowrun/ast/expression.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,12 @@ case class BoolOrComparison(
7676
boolAndComparison: BoolAndComparison,
7777
boolAndComparisons: List[BoolAndComparison]
7878
) {
79-
def collectAtoms: List[Atom] =
79+
def collectAtoms: List[Atom] =
8080
(List(boolAndComparison) ++ boolAndComparisons).flatMap(_.collectAtoms)
8181
}
8282

8383
case class BoolAndComparison(numComparison: NumComparison, numComparisons: List[NumComparisonOpt]) {
84-
def collectAtoms: List[Atom] =
84+
def collectAtoms: List[Atom] =
8585
numComparison.collectAtoms ++ numComparisons.flatMap(_.collectAtoms)
8686
}
8787

@@ -97,15 +97,15 @@ case class Term(factor: Factor, factors: List[FactorOpt]) {
9797
def collectAtoms: List[Atom] =
9898
factor.collectAtoms ++ factors.flatMap(_.collectAtoms)
9999
}
100-
case class TermOpt(op: Token, term: Term){
100+
case class TermOpt(op: Token, term: Term) {
101101
def collectAtoms: List[Atom] = term.collectAtoms
102102
}
103103

104-
case class Factor(unary: Unary, unaries: List[UnaryOpt]){
104+
case class Factor(unary: Unary, unaries: List[UnaryOpt]) {
105105
def collectAtoms: List[Atom] =
106106
unary.collectAtoms ++ unaries.flatMap(_.collectAtoms)
107107
}
108-
case class FactorOpt(op: Token, factor: Factor){
108+
case class FactorOpt(op: Token, factor: Factor) {
109109
def collectAtoms: List[Atom] = factor.collectAtoms
110110
}
111111

@@ -115,7 +115,7 @@ enum Unary:
115115

116116
def collectAtoms: List[Atom] = this match
117117
case Unary.Prefixed(op, unary) => unary.collectAtoms
118-
case Unary.Simple(atom) => List(atom)
118+
case Unary.Simple(atom) => List(atom)
119119

120120
case class UnaryOpt(op: Token, unary: Unary) {
121121
def collectAtoms: List[Atom] = unary.collectAtoms

interpreter/shared/src/main/scala/dev/sacode/flowrun/ast/program.scala

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,24 +45,24 @@ case class Program(
4545
def hasInputs: Boolean =
4646
allStmts.exists(_.isInstanceOf[Statement.Input]) ||
4747
usesFunction(PredefinedFunction.ReadInput)
48-
48+
4949
def usesFunction(f: PredefinedFunction): Boolean =
50-
allExprs.exists{exprStr =>
50+
allExprs.exists { exprStr =>
5151
val expr = parseExpr("dummy", exprStr)
5252
expr.collectAtoms.exists {
5353
case fc: Atom.FunctionCall => fc.name == f.name
54-
case _=> false
54+
case _ => false
5555
}
5656
}
57-
57+
5858
private def allStmts: Seq[Statement] = {
5959
def getStatements(s: Statement): Seq[Statement] = s match {
6060
case stmt: Statement.Block =>
6161
stmt.statements.flatMap(getStatements)
6262
case stmt: Statement.If =>
6363
getStatements(stmt.trueBlock) ++ getStatements(stmt.falseBlock)
6464
case stmt: Statement.While =>
65-
getStatements(stmt.body)
65+
getStatements(stmt.body)
6666
case stmt: Statement.DoWhile =>
6767
getStatements(stmt.body)
6868
case stmt: Statement.ForLoop =>
@@ -71,8 +71,8 @@ case class Program(
7171
}
7272
allFunctions.flatMap(_.statements).flatMap(getStatements)
7373
}
74-
75-
private def allExprs : Seq[String] = {
74+
75+
private def allExprs: Seq[String] = {
7676
def getExprs(s: Statement): Seq[String] = s match {
7777
case stmt: Statement.Return =>
7878
stmt.maybeValue.toSeq
@@ -97,7 +97,7 @@ case class Program(
9797
case _ => Seq.empty
9898
}
9999
allStmts.flatMap(getExprs)
100-
}
100+
}
101101

102102
final case class FlowRunConfig(
103103
lang: String,

interpreter/shared/src/main/scala/dev/sacode/flowrun/codegen/CGenerator.scala

Lines changed: 129 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ class CGenerator(val programAst: Program) extends CodeGenerator {
1313

1414
def generate: Try[CodeGenRes] = Try {
1515

16-
addLine("#include <stdio.h>")
1716
addLine("#include <stdbool.h>")
17+
addLine("#include <string.h>")
18+
addLine("#include <stdio.h>")
1819

1920
genMain()
2021
programAst.functions.foreach(genFunction)
@@ -68,12 +69,94 @@ class CGenerator(val programAst: Program) extends CodeGenerator {
6869
case d: Declare =>
6970
val key = SymbolKey(d.name, Symbol.Kind.Variable, d.id)
7071
symTab.add(d.id, key, d.tpe, None)
71-
val initValue = d.initValue.getOrElse(defaultValue(d.tpe))
72-
val initValueExpr = parseGenExpr(initValue)
73-
d.tpe match
74-
case Expression.Type.String =>
75-
addLine(s"char ${d.name}[] = $initValueExpr;", d.id)
76-
case _ => addLine(s"${genType(d.tpe)} ${d.name} = $initValueExpr;", d.id)
72+
/*
73+
int arr[5] = {0};
74+
int m[5][5] = {{0}};
75+
*/
76+
val generatedLine = d.tpe match {
77+
case Type.Void => d.initValue.map(parseGenExpr).getOrElse("{}")
78+
case Type.Integer =>
79+
val initExpr = parseGenExpr(d.initValue.getOrElse("0"))
80+
s"int ${d.name} = $initExpr;"
81+
case Type.Real =>
82+
val initExpr = parseGenExpr(d.initValue.getOrElse("0.0"))
83+
s"double ${d.name} = $initExpr;"
84+
case Type.String =>
85+
val initExpr = parseGenExpr(d.initValue.getOrElse(""" "" """.trim))
86+
s"char ${d.name}[] = $initExpr;"
87+
case Type.Boolean =>
88+
val initExpr = parseGenExpr(d.initValue.getOrElse("false".trim))
89+
s"bool ${d.name} = $initExpr;"
90+
case Type.IntegerArray =>
91+
val dim1 = parseGenExpr(d.lengthValue1)
92+
s"""|int ${d.name}[${dim1}];
93+
|for (int i = 0; i < ${dim1}; i++) {
94+
| ${d.name}[i] = 0;
95+
|}
96+
|""".stripMargin
97+
case Type.RealArray =>
98+
val dim1 = parseGenExpr(d.lengthValue1)
99+
s"""|double ${d.name}[${dim1}];
100+
|for (int i = 0; i < ${dim1}; i++) {
101+
| ${d.name}[i] = 0.0;
102+
|}
103+
|""".stripMargin
104+
case Type.StringArray =>
105+
val dim1 = parseGenExpr(d.lengthValue1)
106+
s"""|char ${d.name}[${dim1}][100];
107+
|for (int i = 0; i < ${dim1}; i++) {
108+
| strcpy(${d.name}[i], "");
109+
|}
110+
|""".stripMargin
111+
case Type.BooleanArray =>
112+
val dim1 = parseGenExpr(d.lengthValue1)
113+
s"""|bool ${d.name}[${dim1}];
114+
|for (int i = 0; i < ${dim1}; i++) {
115+
| ${d.name}[i] = false;
116+
|}
117+
|""".stripMargin
118+
case Type.IntegerMatrix =>
119+
val dim1 = parseGenExpr(d.lengthValue1)
120+
val dim2 = parseGenExpr(d.lengthValue2)
121+
s"""|int ${d.name}[${dim1}];
122+
|for (int i = 0; i < ${dim1}; i++) {
123+
| for (int j = 0; j < ${dim2}; j++) {
124+
| ${d.name}[i][j] = 0;
125+
| }
126+
|}
127+
|""".stripMargin
128+
case Type.RealMatrix =>
129+
val dim1 = parseGenExpr(d.lengthValue1)
130+
val dim2 = parseGenExpr(d.lengthValue2)
131+
s"""|double ${d.name}[${dim1}];
132+
|for (int i = 0; i < ${dim1}; i++) {
133+
| for (int j = 0; j < ${dim2}; j++) {
134+
| ${d.name}[i][j] = 0.0;
135+
| }
136+
|}
137+
|""".stripMargin
138+
case Type.StringMatrix =>
139+
val dim1 = parseGenExpr(d.lengthValue1)
140+
val dim2 = parseGenExpr(d.lengthValue2)
141+
s"""|char ${d.name}[${dim1}][100];
142+
|for (int i = 0; i < ${dim1}; i++) {
143+
| for (int j = 0; j < ${dim2}; j++) {
144+
| strcpy(${d.name}[i][j], "");
145+
| }
146+
|}
147+
|""".stripMargin
148+
case Type.BooleanMatrix =>
149+
val dim1 = parseGenExpr(d.lengthValue1)
150+
val dim2 = parseGenExpr(d.lengthValue2)
151+
s"""|bool ${d.name}[${dim1}];
152+
|for (int i = 0; i < ${dim1}; i++) {
153+
| for (int j = 0; j < ${dim2}; j++) {
154+
| ${d.name}[i][j] = false;
155+
| }
156+
|}
157+
|""".stripMargin
158+
}
159+
addLine(generatedLine)
77160

78161
case Assign(id, name, value) =>
79162
val genValue = parseGenExpr(value)
@@ -93,11 +176,11 @@ class CGenerator(val programAst: Program) extends CodeGenerator {
93176
}
94177
val tpe = Try(symTab.getSymbolVar("", name).tpe).toOption.getOrElse(Type.String)
95178
val (format, pointer) = tpe match
96-
case Expression.Type.String => ("%d", name) // array is pointer
97-
case Expression.Type.Integer => ("%d", s"&${name}")
98-
case Expression.Type.Real => ("%d", s"&${name}")
99-
case Expression.Type.Boolean => ("%d", s"&${name}")
100-
case Expression.Type.Void => throw RuntimeException("Void cannot be entered")
179+
case Type.Integer | Type.IntegerArray | Type.IntegerMatrix => ("%d", s"&${name}")
180+
case Type.Real | Type.RealArray | Type.RealMatrix => ("%d", s"&${name}")
181+
case Type.Boolean | Type.BooleanArray | Type.BooleanMatrix => ("%d", s"&${name}")
182+
case Type.String | Type.StringArray | Type.StringMatrix => ("%d", name) // array is pointer
183+
case Type.Void => sys.error("Void cannot be entered")
101184
addLine(s"""scanf("${format}", ${pointer});""", id)
102185

103186
case Output(id, value, newline) =>
@@ -152,24 +235,27 @@ class CGenerator(val programAst: Program) extends CodeGenerator {
152235
override def predefFun(name: String, genArgs: List[String]): String = {
153236
def argOpt(idx: Int) = genArgs.lift(idx).getOrElse("")
154237
PredefinedFunction.withName(name).get match {
155-
case Abs => s"abs(${argOpt(0)})"
156-
case Floor => s"floor(${argOpt(0)})"
157-
case Ceil => s"ceil(${argOpt(0)})"
158-
case RandomInteger => s"abs(${argOpt(0)})" // TODO
159-
case Sin => s"sin(${argOpt(0)})"
160-
case Cos => s"cos(${argOpt(0)})"
161-
case Tan => s"tan(${argOpt(0)})"
162-
case Ln => s"log(${argOpt(0)})"
163-
case Log10 => s"log10(${argOpt(0)})"
164-
case Log2 => s"log10(${argOpt(0)})/log10(2)"
165-
case Sqrt => s"Math.sqrt(${argOpt(0)})"
166-
case Pow => s"Math.pow(${argOpt(0)}, ${argOpt(1)})"
167-
case Length => s"${argOpt(0)}.length()"
168-
case CharAt => s"${argOpt(0)}.charAt(${argOpt(1)})"
169-
case RealToInteger => s"(int)${argOpt(0)}"
170-
case StringToInteger =>
171-
s"""try { Convert.ToInt32(${argOpt(0)}) } catch (FormatException) { 0 }"""
172-
case ReadInput => "TODO"
238+
case Abs => s"abs(${argOpt(0)})"
239+
case Floor => s"floor(${argOpt(0)})"
240+
case Ceil => s"ceil(${argOpt(0)})"
241+
case RandomInteger => s"(rand() % ${argOpt(0)})"
242+
case Sin => s"sin(${argOpt(0)})"
243+
case Cos => s"cos(${argOpt(0)})"
244+
case Tan => s"tan(${argOpt(0)})"
245+
case Ln => s"log(${argOpt(0)})"
246+
case Log10 => s"log10(${argOpt(0)})"
247+
case Log2 => s"log10(${argOpt(0)})/log10(2)"
248+
case Sqrt => s"Math.sqrt(${argOpt(0)})"
249+
case Pow => s"Math.pow(${argOpt(0)}, ${argOpt(1)})"
250+
case Length => s"${argOpt(0)}.length()"
251+
case CharAt => s"${argOpt(0)}.charAt(${argOpt(1)})"
252+
case RealToInteger => s"(int)${argOpt(0)}"
253+
case StringToInteger => s"atoi(${argOpt(0)})"
254+
case ReadInput => s"""scanf("%s", ${argOpt(0)})"""
255+
case NumRows => s"sizeof(${argOpt(0)}) / sizeof(${argOpt(0)}[0])"
256+
case NumCols =>
257+
val arr = argOpt(0)
258+
s"(sizeof(${arr})/sizeof(${arr}[0][0])) / (sizeof(${arr})/sizeof(${arr}[0]))"
173259
}
174260
}
175261

@@ -180,10 +266,18 @@ class CGenerator(val programAst: Program) extends CodeGenerator {
180266
private def genType(tpe: Expression.Type): String =
181267
import Expression.Type, Type._
182268
tpe match
183-
case Void => "void"
184-
case Integer => "int"
185-
case Real => "double"
186-
case String => "char"
187-
case Boolean => "bool"
269+
case Void => "void"
270+
case Integer => "int"
271+
case IntegerArray => "int"
272+
case IntegerMatrix => "int"
273+
case Real => "double"
274+
case RealArray => "double"
275+
case RealMatrix => "double"
276+
case String => "char"
277+
case StringArray => "char"
278+
case StringMatrix => "char"
279+
case Boolean => "bool"
280+
case BooleanArray => "bool"
281+
case BooleanMatrix => "bool"
188282

189283
}

0 commit comments

Comments
 (0)