forked from denizdikbiyik/LLVM_Compiler_STM2IR
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSTM2IR.py
More file actions
1 lines (1 loc) · 16.5 KB
/
STM2IR.py
File metadata and controls
1 lines (1 loc) · 16.5 KB
1
{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"STM2IR.py","provenance":[],"collapsed_sections":[]},"kernelspec":{"name":"python3","display_name":"Python 3"}},"cells":[{"cell_type":"code","metadata":{"id":"RYFB_pMZbR8Q","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1613495124205,"user_tz":-180,"elapsed":1567,"user":{"displayName":"Deniz DİKBIYIK","photoUrl":"","userId":"07706369359170137388"}},"outputId":"22335145-6c2c-4034-82c1-e70718aefb09"},"source":["import sys\r\n","\r\n","# this class is created to use stack and use its methods\r\n","class Stack:\r\n"," def __init__(self):\r\n"," self.item = []\r\n"," def isEmpty(self):\r\n"," return self.item == []\r\n"," def push(self,value):\r\n"," self.item.insert(0,value)\r\n"," def pop(self):\r\n"," return self.item.pop(0)\r\n"," def peek(self):\r\n"," return self.item[0]\r\n","\r\n","# inputFileOpen function takes the file as parameter and opens it\r\n","import io\r\n","def inputFileOpen(fileName):\r\n"," try:\r\n"," f = io.open(fileName, 'r', encoding='utf8')\r\n"," return f\r\n"," except OSError as osError:\r\n"," print(osError)\r\n"," except UnicodeDecodeError as decodeError:\r\n"," print(decodeError) \r\n","\r\n","input_file = inputFileOpen(\"file.stm\")\r\n","# here the output file is opened with writing type\r\n","output_file = open(\"file.ll\",\"w\")\r\n","lines = input_file.readlines()\r\n","output_writer = inputFileOpen(\"file.ll\")\r\n","\r\n","# operation counter keeps the number of % for lines\r\n","operationCounter = 0\r\n","# varList stores variables\r\n","varList = []\r\n","# var is the part of the line before equal sign\r\n","var = \"\"\r\n","# expression is the part of the line after equal sign\r\n","expression = \"\"\r\n","# result is defined for switcher function which returns add, sub, mul or sdiv\r\n","result = \"\" \r\n","# error is taken from syntaxanalyzer function and if the input file has errors,\r\n","# it does not continue to the other functions\r\n","error = \"no\"\r\n","# postfix is taken from infix to postfix function to which expression is given\r\n","postfix = []\r\n","# token is the operation sign to give to switcher function and get the text of it\r\n","token = \"\"\r\n","tempList = []\r\n","priority = {'+': 1, '-': 1, '*': 2, '/': 2}\r\n","# temporary lists are taken for going over postfix partly\r\n","tempPostfixVar = []\r\n","tempPostfixOp = [] \r\n","tempList = []\r\n","\r\n","# isOperator checks whether operator or not\r\n","def isOperator(x):\r\n"," ops = ['+', '-', '/', '*']\r\n"," return x in ops\r\n","\r\n","# isOperand checks whether operand or not\r\n","def isOperand(ch):\r\n"," return ch.isalnum()\r\n","\r\n","# the three functions below check the characters\r\n","def isOpenParenthesis(ch):\r\n"," return ch == '('\r\n","\r\n","def isCloseParenthesis(ch):\r\n"," return ch == ')'\r\n","\r\n","def isEqualSign(ch):\r\n"," return ch == '='\r\n","\r\n","def switcher(token):\r\n"," # This function returns operators' IR text to write proper expression in ll file\r\n"," global result\r\n"," if (token == \"+\"):\r\n"," result = \"add\"\r\n"," elif (token == \"-\"):\r\n"," result = \"sub\"\r\n"," elif (token == \"/\"):\r\n"," result = \"sdiv\"\r\n"," elif (token == \"*\"):\r\n"," result = \"mul\"\r\n","\r\n","# main function has all functions' call in it\r\n","def main():\r\n"," try:\r\n"," writeHeader()\r\n"," toIRConverter()\r\n"," global output_writer\r\n"," output_file.writelines([\"\\n ret i32 0\"])\r\n"," output_file.writelines([\"\\n}\"])\r\n"," print(output_writer.read())\r\n"," except OSError:\r\n"," print(\"\\nAn error occured.\")\r\n","\r\n","# writeHeader adds header to the output file\r\n","def writeHeader():\r\n"," try:\r\n"," output_file.writelines([\"; ModuleID = 'stm2ir'\", \"\\ndeclare i32 @printf(i8*, ...)\", \r\n"," \"\\n@print.str = constant [4 x i8] c\\\"%d\\\\0A\\\\00\\\"\", \"\\n\\ndefine i32 @main() {\"])\r\n"," except IOError:\r\n"," print(\"\\nAn error occured.\")\r\n","\r\n","# toIRConverter line converter function for each line in input text\r\n","def toIRConverter():\r\n"," global operationCounter\r\n"," operationCounter = 1\r\n"," try:\r\n"," for i in lines:\r\n"," convertLine(i)\r\n"," except OSError:\r\n"," print(\"\\nAn error occured.\")\r\n","\r\n","# syntaxAnalyzer analyzes each lines from the input and checks if there are any syntax errors\r\n","def syntaxAnalyzer(i):\r\n"," try:\r\n"," numLeftPar = 0\r\n"," numRightPar = 0\r\n"," c0 = ''\r\n"," c = ''\r\n"," c1 = ''\r\n"," global error\r\n"," inputLine = i\r\n"," lineLength = len(inputLine)\r\n"," for j in range(0, lineLength):\r\n"," c = inputLine[j]\r\n"," if (isCloseParenthesis(c)):\r\n"," numLeftPar = numLeftPar + 1\r\n"," elif (isOpenParenthesis(c)):\r\n"," numRightPar = numRightPar + 1\r\n"," # this checks if the inspected character is an operator\r\n"," elif (isOperator(c) or isEqualSign(c)):\r\n"," # if the next character is also an operator, there is an error\r\n"," if (j == 0):\r\n"," # this checks if inspected character is at the first index\r\n"," c1 = inputLine[j + 1]\r\n"," if (isOperator(c1) or isEqualSign(c)):\r\n"," print(\"\\nExtra operator error.\")\r\n"," error = \"yes\"\r\n"," elif (j == lineLength - 1):\r\n"," # this checks if inspected character is at the last index\r\n"," c0 = inputLine[j - 1]\r\n"," if (isOperator(c0) or isEqualSign(c)):\r\n"," print(\"\\nExtra operator error.\")\r\n"," error = \"yes\"\r\n"," else:\r\n"," # for other cases of inspected character\r\n"," c0 = inputLine[j - 1]\r\n"," c1 = inputLine[j + 1]\r\n"," if (isOperator(c0) or isEqualSign(c0) or isOperator(c1) or isEqualSign(c1)):\r\n"," print(\"\\nExtra operator error.\")\r\n"," error = \"yes\"\r\n"," # this is resulted with if number of right and left parentheses are not the same, then there is an error\r\n"," if (numRightPar != numLeftPar):\r\n"," print(\"\\nMissing parenthesis error.\")\r\n"," error = \"yes\"\r\n"," except OSError:\r\n"," print(\"\\nAn error occured.\")\r\n","\r\n","# convertLine converts the line to the intermediate representation, prints the representation to the output file via calling other functions\r\n","# it only writes alloca and store text in it, other texts are created by other called functions\r\n","import re\r\n","def convertLine(i):\r\n"," try:\r\n"," syntaxAnalyzer(i)\r\n"," global error\r\n"," global var\r\n"," global expression\r\n"," if error == \"yes\":\r\n"," output_file.writelines([\"\\nThere are some errors in your expression file.\"])\r\n"," else:\r\n"," global varList\r\n"," line = i.replace(\"\\\\s\", \"\")\r\n"," line = line.replace(\"\\s\", \"\")\r\n"," line = line.replace('\\n', \"\")\r\n"," equalSign = \"=\"\r\n"," if equalSign in line:\r\n"," var = line.split(\"=\")[0]\r\n"," expression = line.split(\"=\")[1]\r\n"," # variable is added into the variable list\r\n"," if var not in varList:\r\n"," varList.append(var.strip())\r\n"," output_file.writelines([\"\\n %\" + var.strip() + \" = alloca i32\"])\r\n"," else:\r\n"," # if there is no equals sign, then whole line is an expression\r\n"," expression = line \r\n"," # If expression is numeric, that is, it doesn't have any arithmetic operation,\r\n"," # then intermediate representation is printed\r\n"," expression = expression.replace(\" \", \"\")\r\n"," if var != \"\" and expression.isnumeric():\r\n"," output_file.writelines([\"\\n store i32 \" + expression + \", i32* %\" + var])\r\n"," else:\r\n"," # else, expression is first converted into postfix notation\r\n"," # then the LLVM representation is printed to output file\r\n"," infixToPostfix(expression, line)\r\n"," equalsign = \"=\"\r\n"," if equalsign in line:\r\n"," output_file.writelines([\"\\n store i32 %\" + str (operationCounter-1) + \", i32* %\" + var])\r\n"," except OSError:\r\n"," print(\"\\nAn error occured.\")\r\n","\r\n","# infixToPostfix function converts expression which is the right side of equal sign \r\n","# or the expression without equal sign in the line to postfix\r\n","def infixToPostfix(infixStr, line):\r\n"," global postfix\r\n"," # to be able to divide expression into list of variables and numbers, \r\n"," # expression is divided according to operation signs\r\n"," infixStr = infixStr.replace(\"+\", \"\\n+\\n\")\r\n"," infixStr = infixStr.replace(\"-\", \"\\n-\\n\")\r\n"," infixStr = infixStr.replace(\"*\", \"\\n*\\n\")\r\n"," infixStr = infixStr.replace(\"/\", \"\\n/\\n\")\r\n"," infixStr = infixStr.replace(\"(\", \"\\n(\\n\")\r\n"," infixStr = infixStr.replace(\")\", \"\\n)\\n\")\r\n"," infixStr = infixStr.splitlines()\r\n"," x = \"\"\r\n"," for i in infixStr:\r\n"," x += \" \" + i + \" \"\r\n"," infixStr = x\r\n"," infixStr = infixStr.replace(\" \", \" \")\r\n"," prec = {}\r\n"," prec[\"^\"] = 4\r\n"," prec[\"*\"] = 3\r\n"," prec[\"/\"] = 3\r\n"," prec[\"+\"] = 2\r\n"," prec[\"-\"] = 2\r\n"," prec[\"(\"] = 1\r\n"," opStack = Stack()\r\n"," postfixList = []\r\n"," infixList = infixStr.split()\r\n"," correctData(infixList)\r\n"," for token in infixList:\r\n"," if len(token) > 1:\r\n"," postfixList.append(token)\r\n"," continue\r\n"," if token in \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwyz\":\r\n"," postfixList.append(token)\r\n"," elif token == \"(\":\r\n"," opStack.push(token)\r\n"," elif token == \")\":\r\n"," topToken = opStack.pop()\r\n"," while topToken != \"(\":\r\n"," postfixList.append(topToken)\r\n"," topToken = opStack.pop()\r\n"," else:\r\n"," while (not opStack.isEmpty()) and \\\r\n"," prec[opStack.peek()] >= prec[token]:\r\n"," postfixList.append(opStack.pop())\r\n"," opStack.push(token)\r\n"," while (not opStack.isEmpty()):\r\n"," postfixList.append(opStack.pop())\r\n"," postfixstr = \" \".join(postfixList)\r\n"," list1 = []\r\n"," txt = \"\"\r\n"," nextTxt = \"\"\r\n"," for i in range (0, len(postfixstr)):\r\n"," txt = txt + postfixstr[i]\r\n"," if i != len(postfixstr)-1:\r\n"," nextTxt = postfixstr [i + 1]\r\n"," elif i == len(postfixstr)-1:\r\n"," nextTxt == \" \"\r\n"," if nextTxt == \" \":\r\n"," list1.append(txt.strip())\r\n"," txt = \"\"\r\n"," list1.append(postfixstr[len(postfixstr)-1].strip())\r\n"," postfix = list1\r\n"," postfixInterpreter(line)\r\n","\r\n","def correctData(infixList):\r\n"," # correctData cleans the data if there are spaces between the\r\n"," # operands and parentheses, or multi-digit numbers or both\r\n"," for index, token in enumerate(infixList):\r\n"," if len(token) > 1 and (not token.isalnum()):\r\n"," if len(token) >= 3:\r\n"," rear_index = index + token.index(token[-1])\r\n"," newindex, i = (rear_index, -1) if token[:-1].isalnum() else (index, +1)\r\n"," parenth, rest = (token[0], token[1:]) if token[1:].isalnum() \\\r\n"," else (token[-1], token[:-1])\r\n"," infixList.insert(newindex, parenth)\r\n"," infixList.insert(newindex + i, rest)\r\n"," else:\r\n"," for subindex, subtoken in enumerate(token):\r\n"," infixList.insert(index + subindex, subtoken)\r\n"," infixList.remove(token)\r\n"," return infixList\r\n","\r\n","# postconverter is the function which is called from postfixInterpreter. \r\n","# this can be counted as the hearth of the project because it creates load and operational lines\r\n","def postconverter(varList):\r\n"," global postfix \r\n"," global result\r\n"," global output_writer\r\n"," global operationCounter\r\n"," myOpList = ['+', '-', '*', '/']\r\n"," previousi = \"\"\r\n"," global tempPostfixVar\r\n"," global tempPostfixOp \r\n"," global tempList\r\n"," for i in postfix:\r\n"," if i in myOpList:\r\n"," tempPostfixOp.append(i)\r\n"," postfix = postfix[1:]\r\n"," else:\r\n"," if previousi in myOpList:\r\n"," break\r\n"," else:\r\n"," tempPostfixVar.append(i)\r\n"," postfix = postfix[1:]\r\n"," previousi = i\r\n"," tempPostfixOp.reverse()\r\n"," while len(tempPostfixVar) > 1 and len(tempPostfixOp) > 0:\r\n"," num2 = tempPostfixVar.pop()\r\n"," num2 = num2.replace(\" \", \"\") \r\n"," if num2 in varList or num2 == \"%\":\r\n"," if num2 in varList:\r\n"," output_file.writelines([\"\\n %\" + str (operationCounter) + \" = load i32* %\" + num2])\r\n"," tempList.append(operationCounter)\r\n"," operationCounter = operationCounter + 1 \r\n"," tempWriter2 = tempList.pop()\r\n"," tempWriterToPrint2 = \"%\" + str (tempWriter2)\r\n"," else:\r\n"," tempWriter2 = num2\r\n"," tempWriterToPrint2 = str (num2)\r\n"," num1 = tempPostfixVar.pop()\r\n"," num1 = num1.replace(\" \", \"\")\r\n"," if num1 in varList or num1 == \"%\":\r\n"," if num1 in varList:\r\n"," output_file.writelines([\"\\n %\" + str (operationCounter) + \" = load i32* %\" + num1])\r\n"," tempList.append(operationCounter)\r\n"," operationCounter = operationCounter + 1 \r\n"," tempWriter1 = tempList.pop()\r\n"," tempWriterToPrint1 = \"%\" + str (tempWriter1)\r\n"," else:\r\n"," tempWriter1 = num1\r\n"," tempWriterToPrint1 = str (num1)\r\n"," opTemper = tempPostfixOp.pop()\r\n"," switcher(opTemper)\r\n"," output_file.writelines([\"\\n %\" + str (operationCounter) + \" = \" + result + \" i32 \" + tempWriterToPrint1 + \" ,\" + tempWriterToPrint2]) \r\n"," tempPostfixVar.append(\"%\") \r\n"," tempList.append(operationCounter)\r\n"," operationCounter = operationCounter + 1\r\n"," if len(tempPostfixOp) > 0 and len(tempPostfixVar) > 1:\r\n"," output_file.writelines([\"\\nThere are some errors in your input file.\"])\r\n","\r\n","# postfixInterpreter goes over the postfix and writes IR with the parts of postfix\r\n","# it goes until seeing next operation sign to be able to check operational priority,\r\n","# after analyzing and writing to output file with that part, it continues\r\n","# till the end of postfix until it is being empty\r\n","def postfixInterpreter(line): \r\n"," try:\r\n"," global varList\r\n"," global postfix\r\n"," global tempPostfixVar\r\n"," global tempPostfixOp \r\n"," global tempList\r\n"," global operationCounter\r\n"," tempPostfixVar = []\r\n"," tempPostfixOp = []\r\n"," while len(postfix) > 0:\r\n"," postconverter(varList) \r\n"," equalSign = \"=\"\r\n"," if equalSign not in line:\r\n"," tempWriterNow = tempList.pop()\r\n"," operationCounter = operationCounter + 1\r\n"," output_file.writelines([\"\\n call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @print.str, i32 0, i32 0), i32 %\" + str (tempWriterNow)+')'])\r\n"," except OSError:\r\n"," print(\"\\nAn error occured.\")\r\n","\r\n","main()"],"execution_count":2,"outputs":[{"output_type":"stream","text":["; ModuleID = 'stm2ir'\n","declare i32 @printf(i8*, ...)\n","@print.str = constant [4 x i8] c\"%d\\0A\\00\"\n","\n","define i32 @main() {\n"," %x1 = alloca i32\n"," store i32 3, i32* %x1 \n"," %y = alloca i32\n"," store i32 5, i32* %y\n"," %zvalue = alloca i32\n"," %1 = load i32* %y\n"," %2 = add i32 1 ,%1\n"," %3 = load i32* %x1\n"," %4 = mul i32 %3 ,%2\n"," %5 = add i32 23 ,%4\n"," store i32 %5, i32* %zvalue\n"," call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @print.str, i32 0, i32 0), i32 %5)\n"," %k = alloca i32\n"," %7 = load i32* %y\n"," %8 = load i32* %x1\n"," %9 = sub i32 %8 ,%7\n"," %10 = load i32* %zvalue\n"," %11 = sub i32 %9 ,%10\n"," store i32 %11, i32* %k\n"," %12 = load i32* %y\n"," %13 = mul i32 3 ,%12\n"," %14 = add i32 2 ,5\n"," %15 = mul i32 1 ,%14\n"," %16 = mul i32 %13 ,%15\n"," %17 = load i32* %x1\n"," %18 = add i32 %17 ,%16\n"," store i32 %18, i32* %k\n"," %19 = load i32* %k\n"," %20 = add i32 %19 ,1\n"," call i32 (i8*, ...)* @printf(i8* getelementptr ([4 x i8]* @print.str, i32 0, i32 0), i32 %20)\n"," ret i32 0\n","}\n"],"name":"stdout"}]}]}