I learn C by reading Tanenbaum and Comer's OS books, and I cannot
imagine how putting variable declarations anywhere other than the top of
the function they belong to, would make sense. Unless they are global,
in which case they go in a suitably global header file.
That's the way we always handled declarations in every PL/I shop I worked in. Local declarations always appeared immediately following the PROCEDURE or BEGIN statement that starts the scope to which the declaration applies. PL/I adopted the idea of nested scopes from Algol. One other programming convention we used was to keep variable scopes as localized as possible. Among other things, it makes lifetime analysis easier for the compiler.
Another feature present in PL/I but not in C or most other languages is nested procedures. A nested procedure inherits all of the variables accessible in the scope of the containing procedure in which it's declared. Up-level addressing (use of variables declared outside the nested procedure) is somewhat error prone and less efficient than accessing data via a parameter.
PL/I also supports recursion, something not provided for in the usual IBM S/360 ABI calling convention. A procedure that can be called recursively must be declared with the RECURSIVE attribute. Unlike C, in IBM S/360/370 PL/I recursion was disallowed by default. DEC's ABI for VMS supports recursion by default and so DEC PL/I dropped the RECURSIVE attribute.
PL/I also supports an extended version of Fortran's computed GOTO via label variables. PL/I statements are labeled by name as opposed to Fortran's statement numbers. A label variable can be assigned a statement label value and a GOTO statement using the label variable transfers control to whichever statement label is held in the label variable. Label variables encourage rat's nest programming styles and very much went out of fashion when structured programming came along.
-Paul W.