static const char *NAME = "format_ada"; //===========================// //== This software is ==// //== (c)opyrighted in 1993 ==// //== by Chris Koeritz ==// //== cak0l@Virginia.EDU ==// //===========================// #include "format_ada.h" #include "guards.h" #include "basics.h" #include "y.tab.h" #include // INDENT: the number of spaces that enclosed Ada lines are indented. #define INDENT " " // IN: increases the level of indentation and stores the token causing the // indentation on the indent stack. #define IN(token) \ { int *token_hold = new int; *token_hold = token; \ chunk *to_stuff = new chunk \ (OTHER_OWNED, (byte *)token_hold, sizeof(int)); \ to_stuff->take_possession(); \ indent_level++; indenting_stack.push(to_stuff); } // OUT: decreases the level of indentation and removes the top of the stack. #define OUT { indent_level--; indenting_stack.pop(); } // CR: adds a carriage return after the symbol to be formatted. #define CR { to_add_after += cr; when_seen = FALSE; } // DENT: indicates that the next time a token is formatted, an indentation // should be included before it. #define DENT indent_soon = TRUE // NONE_BEFORE: indicates that this token does not need a space before it // is printed out. #define NONE_BEFORE space_needed = FALSE; // NONE_AFTER: indicates that this token does not need a space after it. #define NONE_AFTER dont_space_after = TRUE; // REVISE_INDENT: modifies the indentation that was previously used so that // a new level can be accomodated. #define REVISE_INDENT { to_add_before = ""; to_add_before = indent(); } // USE_TRIGGER: if the trigger_extra_cr flag is true, then it is chowed upon // and the old value is stored in had_trigger_for_extra_cr. the extra cr is // generated. #define USE_TRIGGER \ { if (trigger_extra_cr) { \ /*printf("{trigger}");*/ \ CR; \ trigger_extra_cr = FALSE; \ had_trigger_for_extra_cr = TRUE; \ } else { \ had_trigger_for_extra_cr = FALSE; \ } \ } // CREATE_BLOCK: adds a new nested block to the stack of blocks. #define CREATE_BLOCK { block_nesting++; \ printf("creating block %d at indent %d\n", block_nesting, indent_level); \ formatting_stack *new_chunk = new formatting_stack; \ new_chunk->ending_indentation_level = indent_level; \ new_chunk->handlers = FALSE; \ new_chunk->first_semicolon_after_header = FALSE; \ new_chunk->header_seen = FALSE; \ push(new_chunk); } format_ada::format_ada() : space_needed(FALSE), indent_soon(FALSE), indent_level(0), last_formatted_token(0), penult_formatted_token(0), paren_nesting(0), block_nesting(0), when_seen(FALSE), trigger_extra_cr(FALSE), had_trigger_for_extra_cr(FALSE), type_is_coming_up(FALSE), enum_def_occurring(FALSE) {} format_ada::~format_ada() { if (size() != 0) deadly_error(NAME, "~format_ada", "a block has not been closed"); } string &format_ada::indent() { string indentation(INDENT); string *spaces_for_indent = new string; for (int i = 0; i < indent_level; i++) *spaces_for_indent += indentation; return *spaces_for_indent; } format_ada::formatting_stack *format_ada::grab_top(char *error_place) { formatting_stack *ftop; if (size() == 0) deadly_error(NAME, error_place, "no stack element to get"); else ftop = (formatting_stack *)top(); return ftop; } void format_ada::end_block() { if (size() > 0) { formatting_stack *ftop = grab_top("end_block"); if ( (!ftop->handlers && (indent_level == ftop->ending_indentation_level) ) || (ftop->handlers && (indent_level - 1 == ftop->ending_indentation_level) ) ) { //printf("removing block %d at indent %d\n", block_nesting, ftop->ending_indentation_level); block_nesting--; trigger_extra_cr = TRUE; if (ftop->handlers) { OUT; ftop->handlers = FALSE; } delete ftop; pop(); } } else deadly_error(NAME, "end_block", "a block end without a stack item"); } string &format_ada::format(int token, string &token_text) { string cr('\n'); // dont_space_after: if TRUE, then the word after this one should not get a // space in front of it either. int dont_space_after = FALSE; string to_add_before; if (indent_soon) { to_add_before = indent(); indent_soon = FALSE; } string to_add_after; if (token_text.length() == 0) { NONE_BEFORE; NONE_AFTER; } if ( (penult_formatted_token != OR_) && (last_formatted_token == ELSE_) && (token != IF_) ) { NONE_BEFORE; REVISE_INDENT; to_add_before = cr + to_add_before; } switch (token) { case BEGIN_: { formatting_stack *ftop = grab_top("format: begin"); if (!ftop->header_seen) CREATE_BLOCK; ftop = grab_top("format: 2nd begin"); ftop->header_seen = FALSE; OUT; REVISE_INDENT; IN(token); NONE_AFTER; NONE_BEFORE; //printf("{begin}"); CR; DENT; } break; case TYPE_: type_is_coming_up = TRUE; break; case CASE_: break; case RECORD_: if (last_formatted_token != END_) { IN(token); //printf("{record}"); CR; DENT; NONE_AFTER; } else { trigger_extra_cr = TRUE; } break; case ELSE_: if (last_formatted_token != OR_) { OUT; REVISE_INDENT; IN(token); } break; case PRAGMA_: trigger_extra_cr = TRUE; break; case SEMICOLON: { had_trigger_for_extra_cr = FALSE; if (paren_nesting == 0) { printf("!!!"); CR; DENT; NONE_AFTER; if (size()) { formatting_stack *ftop = grab_top("format: semicolon"); if (ftop->header_seen && ftop->first_semicolon_after_header && ( (last_formatted_token == RIGHT_PAREN) || (last_formatted_token == IDENTIFIER) ) ) { //printf("<; end blk>"); end_block(); } ftop->first_semicolon_after_header = FALSE; } } else if (enum_def_occurring) { //printf("{enumdef}"); CR; DENT; NONE_AFTER; } else USE_TRIGGER; enum_def_occurring = FALSE; NONE_BEFORE; } break; case R_LBL_: //printf("{r_lbl}"); CR; DENT; NONE_AFTER; case ARROW_: if (when_seen) { when_seen = FALSE; IN(token); //printf("{arrow}"); CR; DENT; NONE_AFTER; } break; case IS_: if (type_is_coming_up) { type_is_coming_up = FALSE; break; } else USE_TRIGGER; // intentional fall through to THEN_ case. case THEN_: IN(token); //printf("{then}"); CR; DENT; NONE_AFTER; break; case LOOP_: if (last_formatted_token != END_) { IN(token); //printf("{loop}"); CR; DENT; } NONE_AFTER; break; case COLON: if (paren_nesting == 0) { // need to reset the first semicolon flag since a declaration is being // seen. //printf(""); formatting_stack *ftop = grab_top("format: colon"); ftop->first_semicolon_after_header = FALSE; } break; case EXCEPTION_: if (last_formatted_token != COLON) { formatting_stack *ftop = grab_top("format: exception handlers"); ftop->handlers = TRUE; OUT; REVISE_INDENT; IN(token); //printf("{exception}"); CR; DENT; NONE_AFTER; IN(token); } break; case END_: OUT; end_block(); if (type_is_coming_up) { // the end for a type definition must go back more. type_is_coming_up = FALSE; } REVISE_INDENT; break; case RIGHT_PAREN: paren_nesting--; NONE_BEFORE; break; case COMMA: NONE_BEFORE; break; case COMMENT_: USE_TRIGGER; NONE_BEFORE; NONE_AFTER; DENT; break; case LEFT_PAREN: paren_nesting++; if (type_is_coming_up) { enum_def_occurring = TRUE; trigger_extra_cr = TRUE; NONE_AFTER; } else if (last_formatted_token == ASSIGN_) { NONE_AFTER; } else { NONE_BEFORE; NONE_AFTER; } if (last_formatted_token == IS_) space_needed = TRUE; break; case PERIOD: case APOSTROPHE: case DBLDOT_: NONE_AFTER; NONE_BEFORE; break; case WHEN_: { when_seen = TRUE; OUT; REVISE_INDENT; formatting_stack *ftop = grab_top("format: when"); //if (!ftop->handlers) trigger_extra_cr = FALSE; } break; case TASK_: case PACKAGE_: trigger_extra_cr = TRUE; // intentional fall through to proc, func, and decl. case PROCEDURE_: case FUNCTION_: case DECLARE_: if ( (indent_level > 0) && !had_trigger_for_extra_cr) { string temp; temp = to_add_before; //printf("{procsetc}"); to_add_before = cr; to_add_before += temp; } CREATE_BLOCK; if (token == DECLARE_) { USE_TRIGGER; IN(token); //printf("{in for procsetc}"); CR; DENT; NONE_AFTER; } { formatting_stack *ftop = grab_top("format: block header"); ftop->header_seen = TRUE; ftop->first_semicolon_after_header = TRUE; } break; default: break; } if (indent_level < 0) deadly_error(NAME, "format", "problem in indent"); // construction of the string to be returned begins. string sp(' '); if (space_needed) { space_needed = FALSE; to_add_before += sp; } to_add_before += token_text; to_add_before += to_add_after; if (!dont_space_after) space_needed = TRUE; penult_formatted_token = last_formatted_token; last_formatted_token = token; string *to_return = new string(to_add_before); return *to_return; }