Exemplo n.º 1
0
        /// <summary>
        /// Process the "while" statement at "intermediate_code[index]".
        /// </summary>
        void process_while_statement(ref int index)
        {
            int start_while     = statements.Count;
            int end_while_label = LabelAddresses.allocate_label();

            int start_index = index + 1;

            // "start_index" is pointing to the first "while" statement, which marks
            // the start of the while loop. The "while conditional:" line is further down.
            // Search for the "while conditional:" line.
            int conditional_index = start_index;

            while (conditional_index < intermediate_code.Length)
            {
                if (intermediate_code[conditional_index][0].type == TokenType.While)
                {
                    break;
                }
                conditional_index++;
            }

            // Generate statement for the code from "start_index" to
            // "conditional_index"-1, if necessary
            if (start_index < conditional_index)
            {
                construct_statements(start_index, conditional_index - 1, -1 * end_while_label, start_while);
            }

            // Generate statement for the "while conditional:" line
            var conditional_line = intermediate_code[conditional_index];
            int true_addr        = statements.Count + 1;

            statements.Add(new ConditionalStatement(conditional_line, true_addr, -1 * end_while_label));

            // Find the end of the "while" body
            int end_index = find_next_line_with_equal_or_less_indentation(conditional_index);

            // Check for empty "while" body block
            if (end_index - conditional_index <= 1)
            {
                throw new Exception("The while statement body is empty.");
            }

            // Generate statement for the "while" body
            construct_statements(conditional_index + 1, end_index - 1, break_addr: -1 * end_while_label,
                                 continue_addr: start_while);

            // Generate statement for the end of the "while" body
            int indentation = conditional_line.indentation + 4;
            int line_number = intermediate_code[end_index - 1].line_number;

            statements.Add(new JumpStatement(start_while, indentation, line_number));

            index = end_index;
            LabelAddresses.set_label_address(end_while_label, statements.Count);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Process the "for" statement at "intermediate_code[index]".
        /// </summary>
        void process_for_statement(ref int index)
        {
            var for_statement = intermediate_code[index];

            // extract the iterator and iteration variable
            var iteration_var = for_statement[1];
            var iterator      = for_statement[3];

            // add statement to reset the iterator
            statements.Add(new FunctionCallStatement(iterator.ToString(), "reset", null,
                                                     for_statement.indentation, for_statement.line_number));

            // mark the start of the for statement
            int start_for = statements.Count;

            // call iterator.has_next_element()
            statements.Add(new FunctionCallStatement(iterator.ToString(), "has_next_element", null,
                                                     for_statement.indentation, for_statement.line_number));

            // add conditional for the "for" decision
            int end_for_label = LabelAddresses.allocate_label();

            var for_condition = new TokenList(for_statement.line_number, for_statement.indentation);

            for_condition.add_token(Token.Constants.If);
            for_condition.add_token(Token.create_system_var("$return"));
            for_condition.add_token(Token.Constants.Colon);

            int true_addr = statements.Count + 1;

            statements.Add(new ConditionalStatement(for_condition, true_addr, -1 * end_for_label));

            // call iterator.next_element()
            statements.Add(new FunctionCallStatement(iterator.ToString(), "next_element", null,
                                                     for_statement.indentation, for_statement.line_number));

            // iteration_var = iterator
            var assign_iteration_var = new TokenList(for_statement.line_number, for_statement.indentation);

            assign_iteration_var.add_token(iteration_var);
            assign_iteration_var.add_token(Token.Constants.Assign);
            assign_iteration_var.add_token(Token.create_system_var("$return"));

            statements.Add(new AssignStatement(assign_iteration_var));

            // identify the for loop body
            int end_index = find_next_line_with_equal_or_less_indentation(index);

            // Check for empty "for" body block
            if (end_index - index <= 1)
            {
                throw new Exception("The for statement body is empty.");
            }

            // generate code for "for" loop body
            construct_statements(index + 1, end_index - 1, break_addr: -1 * end_for_label,
                                 continue_addr: start_for);

            // generate Jump at the end of the "for" loop body
            int indentation = for_statement.indentation + 4;
            int line_number = intermediate_code[end_index - 1].line_number;

            statements.Add(new JumpStatement(start_for, indentation, line_number));

            index = end_index;
            LabelAddresses.set_label_address(end_for_label, statements.Count);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Process the "if" statement at "intermediate_code[index]".
        /// </summary>
        void process_if_statement(ref int index, int?break_addr, int?continue_addr)
        {
            int  end_if_final_label = LabelAddresses.allocate_label();
            bool final_if_block     = false;

            while (final_if_block == false)
            {
                // "index" points to the current "if" line
                // Find the end of the current if block
                int end_index = find_next_line_with_equal_or_less_indentation(index);

                var current_if_line = intermediate_code[index];

                TokenList next_block_line = null;
                if (end_index < intermediate_code.Length)
                {
                    next_block_line = intermediate_code[end_index];
                }

                // Determine whether "next_block_line" is a continuation of the "if" statement.
                if (next_block_line == null)
                {
                    final_if_block = true; // end of the program
                }
                else if (next_block_line[0].type != TokenType.Elif &&
                         next_block_line[0].type != TokenType.Else)
                {
                    final_if_block = true; // something other than "elif" and "else"
                }
                else if (next_block_line.indentation < current_if_line.indentation)
                {
                    final_if_block = true; // end of if block due to indentation
                }
                // end_if_final --- label ID for the final "if" block's end address
                // end_if --- label ID for the current "if" block's end address
                int end_if_label = end_if_final_label;
                if (final_if_block == false)
                {
                    end_if_label = LabelAddresses.allocate_label();
                }

                // Generate statement for the current if line
                if (current_if_line[0].type == TokenType.If ||
                    current_if_line[0].type == TokenType.Elif)
                {
                    int true_addr = statements.Count + 1;
                    statements.Add(new ConditionalStatement(current_if_line, true_addr, -1 * end_if_label));
                }
                else if (current_if_line[0].type == TokenType.Else)
                {
                    // do nothing
                }

                // Check for empty "if" body block
                if (end_index - index <= 1)
                {
                    if (current_if_line[0].type == TokenType.If)
                    {
                        throw new Exception("The if statement body is empty.");
                    }
                    else if (current_if_line[0].type == TokenType.Elif)
                    {
                        throw new Exception("The elif statement body is empty.");
                    }
                    else
                    {
                        throw new Exception("The else statement body is empty.");
                    }
                }

                // Generate statements for the "if" block body
                construct_statements(index + 1, end_index - 1, break_addr, continue_addr);

                // Generate statement for the end of the "if" block
                if (final_if_block == false)
                {
                    int indentation = intermediate_code[end_index - 1].indentation;
                    int line_number = intermediate_code[end_index - 1].line_number;
                    statements.Add(new JumpStatement(-1 * end_if_final_label, indentation, line_number));
                }

                // Record the current address as the "end_if" address
                LabelAddresses.set_label_address(end_if_label, statements.Count);

                // Set "index" for the future
                index = end_index;
            }

            LabelAddresses.set_label_address(end_if_final_label, statements.Count);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Process the "for" statement at "intermediate_code[index]".
        /// </summary>
        void process_def_statement(ref int index)
        {
            var def_statement = intermediate_code[index];

            // A jump statement that goes to the end of the function
            int end_func_label = LabelAddresses.allocate_label();

            statements.Add(new JumpStatement(-1 * end_func_label, def_statement.indentation, def_statement.line_number));

            // Syntax and assumption check
            if (def_statement[1].type != TokenType.Identifier)
            {
                throw new Exception("Function definition syntax error. \""
                                    + def_statement[1].ToString() + "\" not an identifier.");
            }

            if (def_statement[2].type != TokenType.Left_Paren)
            {
                throw new Exception("Function definition syntax error. \""
                                    + def_statement[2].ToString() + "\" is expected to be '('.");
            }

            if (def_statement[-1].type != TokenType.Colon)
            {
                throw new Exception("Function definition syntax error. \""
                                    + "The function definition does not end with ':'.");
            }

            if (def_statement[-2].type != TokenType.Right_Paren)
            {
                throw new Exception("Function definition syntax error. \""
                                    + "The second last character is expected to be ')'.");
            }

            // Process function name
            string function_name = (string)def_statement[1].value;

            if (user_def_function_locations.ContainsKey(function_name))
            {
                throw new Exception("The function name \"" + function_name + "\" is already in use.");
            }

            user_def_function_locations.Add(function_name, statements.Count);

            // Create a function argument assignment statement for each argument
            int arg_index       = 3; // def f ( arg0 -- start at arg0, token #3
            int position_number = 0;

            while (arg_index < def_statement.Count - 2)
            {
                // check that arg_index is an identifier token
                if (def_statement[arg_index].type != TokenType.Identifier)
                {
                    throw new Exception("Syntax error in function arguments. Expecting \""
                                        + def_statement[arg_index].ToString() + "\" to be a variable name.");
                }

                // simple argument case - without default argument, it's either [arg0 ,] or [arg0 )]
                if (def_statement[arg_index + 1].type == TokenType.Comma ||
                    def_statement[arg_index + 1].type == TokenType.Right_Paren)
                {
                    statements.Add(new FunctionArgAssignStatement(position_number, def_statement, arg_index, arg_index));
                    arg_index += 2;
                    position_number++;
                }

                // simple argument plus type hint: [arg0 : str]
                else if (def_statement[arg_index + 1].type == TokenType.Colon &&
                         def_statement[arg_index + 2].type == TokenType.Identifier &&
                         (def_statement[arg_index + 3].type == TokenType.Comma ||
                          def_statement[arg_index + 3].type == TokenType.Right_Paren))
                {
                    statements.Add(new FunctionArgAssignStatement(position_number, def_statement, arg_index, arg_index));
                    arg_index += 4;
                    position_number++;
                }

                // default argument case
                else if (def_statement[arg_index + 1].type == TokenType.Assign)
                {
                    // The end of the default argument could be a ',' or a ')'.
                    // In the case of ')', need to track '(' and ')' balance - since
                    // "x=(1+2)*3" is allowed in the default argument.
                    int arg_end_index = arg_index + 2;
                    int paren_balance = 0; // +1 for every '(' seen

                    while (arg_end_index < def_statement.Count - 1)
                    {
                        // t = current token
                        var t = def_statement[arg_end_index];

                        if (t.type == TokenType.Comma)
                        {
                            break;
                        }
                        else if (t.type == TokenType.Left_Paren)
                        {
                            paren_balance++;
                        }
                        else if (t.type == TokenType.Right_Paren)
                        {
                            paren_balance--;
                            if (paren_balance < 0)
                            {
                                break;
                            }
                        }

                        arg_end_index++;
                    }

                    // Look for errors with "arg_end_index"
                    // Check for parenthesis imbalance
                    if (def_statement[arg_end_index].type == TokenType.Comma &&
                        paren_balance != 0)
                    {
                        throw new Exception("The default argument has parenthesis imbalance.");
                    }

                    if (def_statement[arg_end_index].type == TokenType.Right_Paren &&
                        paren_balance != -1)
                    {
                        throw new Exception("The default argument has parenthesis imbalance.");
                    }

                    // Check empty default statement
                    if (arg_end_index == arg_index + 2)
                    {
                        throw new Exception("The default argument statement is empty.");
                    }

                    // Add argument assignment statement
                    statements.Add(new FunctionArgAssignStatement(position_number, def_statement, arg_index, arg_end_index - 1));
                    arg_index = arg_end_index + 1;
                    position_number++;
                }

                else
                {
                    throw new Exception("Syntax error in function arguments.");
                }
            }

            // Look for the end of the function block
            int end_index = find_next_line_with_equal_or_less_indentation(index);

            // Check for empty "def" body block
            if (end_index - index <= 1)
            {
                throw new Exception("The " + def_statement.ToString().Trim()
                                    + " statement body is empty.");
            }

            // Generate statements for the function body
            construct_statements(index + 1, end_index - 1, null, null);

            // If there is no return statement, add one
            var last_func_statement = statements[statements.Count - 1];

            if (last_func_statement.Type != StatementType.Return)
            {
                statements.Add(new ReturnStatement(last_func_statement.Indentation, last_func_statement.LineNumber));
            }

            index = end_index;
            LabelAddresses.set_label_address(end_func_label, statements.Count);
        }